Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Hans Hörberg
2014-02-28 08:30:27 +01:00
17 changed files with 70400 additions and 53 deletions

View File

@@ -844,6 +844,14 @@ def extension_elements_to_elements(extension_elements, schemas):
according to the schemas. according to the schemas.
""" """
res = [] res = []
if isinstance(schemas, list):
pass
elif isinstance(schemas, dict):
schemas = schemas.values()
else:
return res
for extension_element in extension_elements: for extension_element in extension_elements:
for schema in schemas: for schema in schemas:
inst = extension_element_to_element(extension_element, inst = extension_element_to_element(extension_element,

View File

@@ -117,7 +117,8 @@ class Saml2Client(Base):
entity_ids = self.users.issuers_of_info(name_id) entity_ids = self.users.issuers_of_info(name_id)
return self.do_logout(name_id, entity_ids, reason, expire, sign) return self.do_logout(name_id, entity_ids, reason, expire, sign)
def do_logout(self, name_id, entity_ids, reason, expire, sign=None): def do_logout(self, name_id, entity_ids, reason, expire, sign=None,
expected_binding=None):
""" """
:param name_id: Identifier of the Subject (a NameID instance) :param name_id: Identifier of the Subject (a NameID instance)
@@ -126,6 +127,8 @@ class Saml2Client(Base):
:param reason: The reason for doing the logout :param reason: The reason for doing the logout
:param expire: Try to logout before this time. :param expire: Try to logout before this time.
:param sign: Whether to sign the request or not :param sign: Whether to sign the request or not
:param expected_binding: Specify the expected binding then not try it
all
:return: :return:
""" """
# check time # check time
@@ -142,6 +145,8 @@ class Saml2Client(Base):
# for all where I can use the SOAP binding, do those first # for all where I can use the SOAP binding, do those first
for binding in [BINDING_SOAP, BINDING_HTTP_POST, for binding in [BINDING_SOAP, BINDING_HTTP_POST,
BINDING_HTTP_REDIRECT]: BINDING_HTTP_REDIRECT]:
if expected_binding and binding != expected_binding:
continue
try: try:
srvs = self.metadata.single_logout_service(entity_id, srvs = self.metadata.single_logout_service(entity_id,
binding, binding,

View File

@@ -2,6 +2,7 @@
__author__ = 'rolandh' __author__ = 'rolandh'
import copy
import sys import sys
import os import os
import re import re
@@ -48,7 +49,7 @@ ONTS = {
COMMON_ARGS = [ COMMON_ARGS = [
"entityid", "xmlsec_binary", "debug", "key_file", "cert_file", "entityid", "xmlsec_binary", "debug", "key_file", "cert_file",
"secret", "accepted_time_diff", "name", "ca_certs", "encryption_type", "secret", "accepted_time_diff", "name", "ca_certs",
"description", "valid_for", "verify_ssl_cert", "description", "valid_for", "verify_ssl_cert",
"organization", "organization",
"contact_person", "contact_person",
@@ -175,6 +176,7 @@ class Config(object):
self.debug = False self.debug = False
self.key_file = None self.key_file = None
self.cert_file = None self.cert_file = None
self.encryption_type = 'both'
self.secret = None self.secret = None
self.accepted_time_diff = None self.accepted_time_diff = None
self.name = None self.name = None
@@ -349,7 +351,7 @@ class Config(object):
mod = self._load(config_file) mod = self._load(config_file)
#return self.load(eval(open(config_file).read())) #return self.load(eval(open(config_file).read()))
return self.load(mod.CONFIG, metadata_construction) return self.load(copy.deepcopy(mod.CONFIG), metadata_construction)
def load_metadata(self, metadata_conf): def load_metadata(self, metadata_conf):
""" Loads metadata into an internal structure """ """ Loads metadata into an internal structure """

View File

@@ -291,7 +291,8 @@ class Entity(HTTPBase):
def unravel(self, txt, binding, msgtype="response"): def unravel(self, txt, binding, msgtype="response"):
#logger.debug("unravel '%s'" % txt) #logger.debug("unravel '%s'" % txt)
if binding not in [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST, if binding not in [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST,
BINDING_SOAP, BINDING_URI, None]: BINDING_SOAP, BINDING_URI, BINDING_HTTP_ARTIFACT,
None]:
raise ValueError("Don't know how to handle '%s'" % binding) raise ValueError("Don't know how to handle '%s'" % binding)
else: else:
try: try:
@@ -302,6 +303,8 @@ class Entity(HTTPBase):
elif binding == BINDING_SOAP: elif binding == BINDING_SOAP:
func = getattr(soap, "parse_soap_enveloped_saml_%s" % msgtype) func = getattr(soap, "parse_soap_enveloped_saml_%s" % msgtype)
xmlstr = func(txt) xmlstr = func(txt)
elif binding == BINDING_HTTP_ARTIFACT:
xmlstr = base64.b64decode(txt)
else: else:
xmlstr = txt xmlstr = txt
except Exception: except Exception:

View File

@@ -120,6 +120,9 @@ class IdentDB(object):
_id = "%s@%s" % (_id, self.domain) _id = "%s@%s" % (_id, self.domain)
if nformat == NAMEID_FORMAT_PERSISTENT:
_id = userid
nameid = NameID(format=nformat, sp_name_qualifier=sp_name_qualifier, nameid = NameID(format=nformat, sp_name_qualifier=sp_name_qualifier,
name_qualifier=name_qualifier, text=_id) name_qualifier=name_qualifier, text=_id)
@@ -281,7 +284,7 @@ class IdentDB(object):
# else create and return a new one # else create and return a new one
return self.construct_nameid(_id, name_id_policy=name_id_policy) return self.construct_nameid(_id, name_id_policy=name_id_policy)
def handle_manage_name_id_request(self, name_id, new_id="", def handle_manage_name_id_request(self, name_id, new_id=None,
new_encrypted_id="", terminate=""): new_encrypted_id="", terminate=""):
""" """
Requests from the SP is about the SPProvidedID attribute. Requests from the SP is about the SPProvidedID attribute.

View File

@@ -103,12 +103,13 @@ def repack_cert(cert):
class MetaData(object): class MetaData(object):
def __init__(self, onts, attrc, metadata=""): def __init__(self, onts, attrc, metadata="", node_name=None, **kwargs):
self.onts = onts self.onts = onts
self.attrc = attrc self.attrc = attrc
self.entity = {} self.entity = {}
self.metadata = metadata self.metadata = metadata
self.security = None self.security = None
self.node_name = node_name
def items(self): def items(self):
return self.entity.items() return self.entity.items()
@@ -371,8 +372,8 @@ class MetaDataFile(MetaData):
Handles Metadata file on the same machine. The format of the file is Handles Metadata file on the same machine. The format of the file is
the SAML Metadata format. the SAML Metadata format.
""" """
def __init__(self, onts, attrc, filename, cert=None): def __init__(self, onts, attrc, filename, cert=None, **kwargs):
MetaData.__init__(self, onts, attrc) MetaData.__init__(self, onts, attrc, **kwargs)
self.filename = filename self.filename = filename
self.cert = cert self.cert = cert
@@ -382,8 +383,9 @@ class MetaDataFile(MetaData):
def load(self): def load(self):
_txt = self.get_metadata_content() _txt = self.get_metadata_content()
if self.cert: if self.cert:
node_name = "%s:%s" % (md.EntitiesDescriptor.c_namespace, node_name = self.node_name \
md.EntitiesDescriptor.c_tag) or "%s:%s" % (md.EntitiesDescriptor.c_namespace,
md.EntitiesDescriptor.c_tag)
if self.security.verify_signature(_txt, if self.security.verify_signature(_txt,
node_name=node_name, node_name=node_name,
@@ -400,8 +402,8 @@ class MetaDataLoader(MetaDataFile):
Handles Metadata file loaded by a passed in function. Handles Metadata file loaded by a passed in function.
The format of the file is the SAML Metadata format. The format of the file is the SAML Metadata format.
""" """
def __init__(self, onts, attrc, loader_callable, cert=None): def __init__(self, onts, attrc, loader_callable, cert=None, **kwargs):
MetaData.__init__(self, onts, attrc) MetaData.__init__(self, onts, attrc, **kwargs)
self.metadata_provider_callable = self.get_metadata_loader(loader_callable) self.metadata_provider_callable = self.get_metadata_loader(loader_callable)
self.cert = cert self.cert = cert
@@ -444,7 +446,7 @@ class MetaDataExtern(MetaData):
Accessible but HTTP GET. Accessible but HTTP GET.
""" """
def __init__(self, onts, attrc, url, security, cert, http): def __init__(self, onts, attrc, url, security, cert, http, **kwargs):
""" """
:params onts: :params onts:
:params attrc: :params attrc:
@@ -453,7 +455,7 @@ class MetaDataExtern(MetaData):
:params cert: :params cert:
:params http: :params http:
""" """
MetaData.__init__(self, onts, attrc) MetaData.__init__(self, onts, attrc, **kwargs)
self.url = url self.url = url
self.security = security self.security = security
self.cert = cert self.cert = cert
@@ -466,8 +468,9 @@ class MetaDataExtern(MetaData):
""" """
response = self.http.send(self.url) response = self.http.send(self.url)
if response.status_code == 200: if response.status_code == 200:
node_name = "%s:%s" % (md.EntitiesDescriptor.c_namespace, node_name = self.node_name \
md.EntitiesDescriptor.c_tag) or "%s:%s" % (md.EntitiesDescriptor.c_namespace,
md.EntitiesDescriptor.c_tag)
_txt = response.text.encode("utf-8") _txt = response.text.encode("utf-8")
if self.cert: if self.cert:
@@ -480,7 +483,7 @@ class MetaDataExtern(MetaData):
self.parse(_txt) self.parse(_txt)
return True return True
else: else:
logger.info("Response status: %s" % response.status) logger.info("Response status: %s" % response.status_code)
return False return False
@@ -489,8 +492,8 @@ class MetaDataMD(MetaData):
Handles locally stored metadata, the file format is the text representation Handles locally stored metadata, the file format is the text representation
of the Python representation of the metadata. of the Python representation of the metadata.
""" """
def __init__(self, onts, attrc, filename): def __init__(self, onts, attrc, filename, **kwargs):
MetaData.__init__(self, onts, attrc) MetaData.__init__(self, onts, attrc, **kwargs)
self.filename = filename self.filename = filename
def load(self): def load(self):
@@ -523,12 +526,13 @@ class MetadataStore(object):
elif typ == "inline": elif typ == "inline":
self.ii += 1 self.ii += 1
key = self.ii key = self.ii
md = MetaData(self.onts, self.attrc, args[0]) md = MetaData(self.onts, self.attrc, args[0], **kwargs)
elif typ == "remote": elif typ == "remote":
key = kwargs["url"] key = kwargs["url"]
md = MetaDataExtern(self.onts, self.attrc, md = MetaDataExtern(self.onts, self.attrc,
kwargs["url"], self.security, kwargs["url"], self.security,
kwargs["cert"], self.http) kwargs["cert"], self.http,
node_name=kwargs.get('node_name'))
elif typ == "mdfile": elif typ == "mdfile":
key = args[0] key = args[0]
md = MetaDataMD(self.onts, self.attrc, args[0]) md = MetaDataMD(self.onts, self.attrc, args[0])
@@ -804,7 +808,7 @@ class MetadataStore(object):
res = [] res = []
for md in self.metadata.values(): for md in self.metadata.values():
for ent_id, ent_desc in md.items(): for ent_id, ent_desc in md.items():
if "spsso_descriptor" in ent_desc: if descriptor in ent_desc:
res.append(ent_id) res.append(ent_id)
return res return res

View File

@@ -197,7 +197,7 @@ def do_key_descriptor(cert, use="both"):
) )
] ]
elif use in ["signing", "encryption"]: elif use in ["signing", "encryption"]:
md.KeyDescriptor( return md.KeyDescriptor(
key_info=ds.KeyInfo( key_info=ds.KeyInfo(
x509_data=ds.X509Data( x509_data=ds.X509Data(
x509_certificate=ds.X509Certificate(text=cert) x509_certificate=ds.X509Certificate(text=cert)
@@ -429,7 +429,8 @@ def do_spsso_descriptor(conf, cert=None):
spsso.extensions.add_extension_element(val) spsso.extensions.add_extension_element(val)
if cert: if cert:
spsso.key_descriptor = do_key_descriptor(cert, "both") encryption_type = conf.encryption_type
spsso.key_descriptor = do_key_descriptor(cert, encryption_type)
for key in ["want_assertions_signed", "authn_requests_signed"]: for key in ["want_assertions_signed", "authn_requests_signed"]:
try: try:

View File

@@ -153,7 +153,8 @@ class IdentMDB(IdentDB):
self.mdb.store(ident, name_id=to_dict(name_id, ONTS.values(), True)) self.mdb.store(ident, name_id=to_dict(name_id, ONTS.values(), True))
def find_nameid(self, userid, nformat=None, sp_name_qualifier=None, def find_nameid(self, userid, nformat=None, sp_name_qualifier=None,
name_qualifier=None, sp_provided_id=None): name_qualifier=None, sp_provided_id=None, **kwargs):
# reset passed for compatibility kwargs for next usage
kwargs = {} kwargs = {}
if nformat: if nformat:
kwargs["name_format"] = nformat kwargs["name_format"] = nformat

View File

@@ -762,19 +762,28 @@ class AuthnResponse(StatusResponse):
return self._assertion(assertion) return self._assertion(assertion)
def parse_assertion(self): def parse_assertion(self):
try: if self.context == "AuthnQuery":
assert len(self.response.assertion) == 1 or \ # can contain one or more assertions
len(self.response.encrypted_assertion) == 1 pass
except AssertionError: else: # This is a saml2int limitation
raise Exception("No assertion part") try:
assert len(self.response.assertion) == 1 or \
len(self.response.encrypted_assertion) == 1
except AssertionError:
raise Exception("No assertion part")
if self.response.assertion: if self.response.assertion:
logger.debug("***Unencrypted response***") logger.debug("***Unencrypted response***")
return self._assertion(self.response.assertion[0]) for assertion in self.response.assertion:
if not self._assertion(assertion):
return False
return True
else: else:
logger.debug("***Encrypted response***") logger.debug("***Encrypted response***")
return self._encrypted_assertion( for assertion in self.response.encrypted_assertion:
self.response.encrypted_assertion[0]) if not self._encrypted_assertion(assertion):
return False
return True
def verify(self): def verify(self):
""" Verify that the assertion is syntactically correct and """ Verify that the assertion is syntactically correct and
@@ -883,7 +892,7 @@ class AuthnQueryResponse(AuthnResponse):
self.entity_id = entity_id self.entity_id = entity_id
self.attribute_converters = attribute_converters self.attribute_converters = attribute_converters
self.assertion = None self.assertion = None
self.context = "AuthnQueryResponse" self.context = "AuthnQuery"
def condition_ok(self, lax=False): # Should I care about conditions ? def condition_ok(self, lax=False): # Should I care about conditions ?
return True return True

View File

@@ -151,6 +151,10 @@ class Server(Entity):
raise Exception("Couldn't open identity database: %s" % raise Exception("Couldn't open identity database: %s" %
(dbspec,)) (dbspec,))
_domain = self.config.getattr("domain", "idp")
if _domain:
self.ident.domain = _domain
self.ident.name_qualifier = self.config.entityid self.ident.name_qualifier = self.config.entityid
dbspec = self.config.getattr("edu_person_targeted_id", "idp") dbspec = self.config.getattr("edu_person_targeted_id", "idp")
@@ -465,7 +469,14 @@ class Server(Entity):
if not snq: if not snq:
snq = sp_entity_id snq = sp_entity_id
_nids = self.ident.find_nameid(userid, sp_name_qualifier=snq) kwa = {"sp_name_qualifier": snq}
try:
kwa["format"] = name_id_policy.format
except AttributeError:
pass
_nids = self.ident.find_nameid(userid, **kwa)
# either none or one # either none or one
if _nids: if _nids:
name_id = _nids[0] name_id = _nids[0]

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?><EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="INC20140204T195141" Name="urn:mace:incommon" validUntil="2014-02-18T10:00:00Z" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:metadata sstc-saml-schema-metadata-2.0.xsd urn:mace:shibboleth:metadata:1.0 shibboleth-metadata-1.0.xsd http://www.w3.org/2000/09/xmldsig# xmldsig-core-schema.xsd"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <?xml version="1.0" encoding="UTF-8"?><EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="INC20140204T195141" Name="urn:mace:incommon" validUntil="2020-02-18T10:00:00Z" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:metadata sstc-saml-schema-metadata-2.0.xsd urn:mace:shibboleth:metadata:1.0 shibboleth-metadata-1.0.xsd http://www.w3.org/2000/09/xmldsig# xmldsig-core-schema.xsd"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo> <ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
@@ -125457,4 +125457,4 @@ SF+p+s3fUvjA71QwrE3AjKXRHVUkTOk3cr79cC3vKw==
<EmailAddress>security@mghpcc.org</EmailAddress> <EmailAddress>security@mghpcc.org</EmailAddress>
</ContactPerson> </ContactPerson>
</EntityDescriptor> </EntityDescriptor>
</EntitiesDescriptor> </EntitiesDescriptor>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?><EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="AAITest-20140205105921" Name="urn:mace:switch.ch:aaitest" validUntil="2014-02-10T09:59:21Z" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:metadata saml-schema-metadata-2.0.xsd urn:mace:shibboleth:metadata:1.0 shibboleth-metadata-1.0.xsd http://www.w3.org/2000/09/xmldsig# xmldsig-core-schema.xsd"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <?xml version="1.0" encoding="UTF-8"?><EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="AAITest-20140205105921" Name="urn:mace:switch.ch:aaitest" validUntil="2020-02-10T09:59:21Z" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:metadata saml-schema-metadata-2.0.xsd urn:mace:shibboleth:metadata:1.0 shibboleth-metadata-1.0.xsd http://www.w3.org/2000/09/xmldsig# xmldsig-core-schema.xsd"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo> <ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
@@ -11793,4 +11793,4 @@ uO0GTCkBR4o9JvycnNPOWxknPccIms09elaAcgFDQ6o=
<OrganizationURL xml:lang="en">http://www.aai-demo-idp.switch.ch/</OrganizationURL> <OrganizationURL xml:lang="en">http://www.aai-demo-idp.switch.ch/</OrganizationURL>
</Organization> </Organization>
</EntityDescriptor> </EntityDescriptor>
</EntitiesDescriptor> </EntitiesDescriptor>

70292
tests/swamid-2.0.xml Normal file

File diff suppressed because one or more lines are too long

View File

@@ -39,9 +39,11 @@ class TestAC():
for ac in self.acs: for ac in self.acs:
try: try:
ava = ac.fro(ats) ava = ac.fro(ats)
break
except attribute_converter.UnknownNameFormat: except attribute_converter.UnknownNameFormat:
pass pass
# break if we have something
if ava:
break
print ava.keys() print ava.keys()
assert _eq(ava.keys(), ['givenName', 'displayName', 'uid', assert _eq(ava.keys(), ['givenName', 'displayName', 'uid',
'eduPersonNickname', 'street', 'eduPersonNickname', 'street',
@@ -207,4 +209,4 @@ if __name__ == "__main__":
t = TestAC() t = TestAC()
t.setup_class() t.setup_class()
t.test_mixed_attributes_1() t.test_mixed_attributes_1()
#test_noop_attribute_conversion() #test_noop_attribute_conversion()

View File

@@ -96,6 +96,7 @@ class TestIdentifier():
assert _eq(nameid.keyswv(), ['text', 'format', 'sp_name_qualifier', assert _eq(nameid.keyswv(), ['text', 'format', 'sp_name_qualifier',
'name_qualifier']) 'name_qualifier'])
assert nameid.format == NAMEID_FORMAT_TRANSIENT assert nameid.format == NAMEID_FORMAT_TRANSIENT
assert nameid.text != "foobar"
def test_vo_1(self): def test_vo_1(self):
policy = Policy({ policy = Policy({
@@ -119,7 +120,8 @@ class TestIdentifier():
'name_qualifier']) 'name_qualifier'])
assert nameid.sp_name_qualifier == 'http://vo.example.org/biomed' assert nameid.sp_name_qualifier == 'http://vo.example.org/biomed'
assert nameid.format == NAMEID_FORMAT_PERSISTENT assert nameid.format == NAMEID_FORMAT_PERSISTENT
assert nameid.text != "foobar" # we want to keep the user identifier in the nameid node
assert nameid.text == "foobar"
def test_vo_2(self): def test_vo_2(self):
policy = Policy({ policy = Policy({

View File

@@ -74,7 +74,7 @@ def test_metadata():
assert len(certs) == 1 assert len(certs) == 1
sps = mds.with_descriptor("spsso") sps = mds.with_descriptor("spsso")
assert len(sps) == 418 assert len(sps) == 417
wants = mds.attribute_requirement('https://connect.sunet.se/shibboleth') wants = mds.attribute_requirement('https://connect.sunet.se/shibboleth')
assert wants["optional"] == [] assert wants["optional"] == []

View File

@@ -52,17 +52,21 @@ MDIMPORT = {
} }
item = MDIMPORT[sys.argv[1]] def main():
item = MDIMPORT[sys.argv[1]]
metad = None metad = None
if item["type"] == "local": if item["type"] == "local":
metad = MetaDataFile(sys.argv[1], ONTS.values(), item["file"]) metad = MetaDataFile(sys.argv[1], ONTS.values(), item["file"])
elif item["type"] == "external": elif item["type"] == "external":
metad = MetaDataExtern(sys.argv[1], ONTS.values(), metad = MetaDataExtern(sys.argv[1], ONTS.values(),
item["url"], "/opt/local/bin/xmlsec1", item["cert"]) item["url"], "/opt/local/bin/xmlsec1", item["cert"])
if metad: if metad:
metad.load() metad.load()
print metad.dumps() print metad.dumps()
if __name__ == '__main__':
main()