summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Koranda <skoranda@gmail.com>2017-12-24 14:07:37 -0600
committerScott Koranda <skoranda@gmail.com>2018-12-05 05:21:51 -0600
commitb6bf0fae4c735f2f0602b5fda2daeb0c30fa5683 (patch)
tree3c81f0541d06ea0cade667b1a0afc9366af00be1
parent65b136e2c822d3b0e08e0b3c1dc121b6c7de646c (diff)
downloadpysaml2-b6bf0fae4c735f2f0602b5fda2daeb0c30fa5683.tar.gz
Enable signature verification for MDQ
Add functionality to allow configuration of signature verification for metadata obtained using the MDQ protocol. Support is limited to checking the signature of a response containing a single entity and not multiple entities.
-rw-r--r--docs/howto/config.rst25
-rw-r--r--src/saml2/mdstore.py41
2 files changed, 53 insertions, 13 deletions
diff --git a/docs/howto/config.rst b/docs/howto/config.rst
index 274da303..de58ce99 100644
--- a/docs/howto/config.rst
+++ b/docs/howto/config.rst
@@ -183,8 +183,13 @@ the client key in an HTTPS session.
metadata
^^^^^^^^
-Contains a list of places where metadata can be found. This can be either
-a file accessible on the server the service runs on, or somewhere on the net.::
+Contains a list of places where metadata can be found. This can be
+
+* a local file accessible on the server the service runs on
+* a remote URL serving aggregate metadata
+* a metadata query protocol (MDQ) service URL
+
+For example::
"metadata" : {
"local": [
@@ -195,13 +200,19 @@ a file accessible on the server the service runs on, or somewhere on the net.::
"url":"https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2",
"cert":"kalmar2.cert"
}],
+ "mdq": [
+ {
+ "url":"http://mdq.ukfederation.org.uk/",
+ "cert":"ukfederation-mdq.pem"
+ }],
},
-The above configuration means that the service should read two local
-metadata files, and on top of that load one from the net. To verify the
-authenticity of the file downloaded from the net, the local copy of the
-public key should be used.
-This public key must be acquired by some out-of-band method.
+The above configuration means that the service should read two aggregate local
+metadata files, one aggregate metadata file from a remote server, and query a
+remote MDQ server. To verify the authenticity of the metadata aggregate downloaded from the
+remot server and the MDQ server local copies of the metadata signing certificates should be used.
+These public keys must be acquired by some secure out-of-band method before being
+placed on the local file system.
organization
^^^^^^^^^^^^
diff --git a/src/saml2/mdstore.py b/src/saml2/mdstore.py
index ef38c9ac..044a1b59 100644
--- a/src/saml2/mdstore.py
+++ b/src/saml2/mdstore.py
@@ -779,7 +779,10 @@ SAML_METADATA_CONTENT_TYPE = 'application/samlmetadata+xml'
class MetaDataMDX(InMemoryMetaData):
- """ Uses the md protocol to fetch entity information
+ """
+ Uses the MDQ protocol to fetch entity information.
+ The protocol is defined at
+ https://datatracker.ietf.org/doc/draft-young-md-query-saml/
"""
@staticmethod
@@ -787,24 +790,41 @@ class MetaDataMDX(InMemoryMetaData):
return "{{sha1}}{}".format(
hashlib.sha1(entity_id.encode("utf-8")).hexdigest())
- def __init__(self, url, entity_transform=None):
+ def __init__(self, url=None, security=None, cert=None,
+ entity_transform=None, **kwargs):
"""
:params url: mdx service url
+ :params security: SecurityContext()
+ :params cert: certificate used to check signature of signed metadata
:params entity_transform: function transforming (e.g. base64,
sha1 hash or URL quote
hash) the entity id. It is applied to the entity id before it is
concatenated with the request URL sent to the MDX server. Defaults to
sha1 transformation.
"""
- super(MetaDataMDX, self).__init__(None, '')
+ super(MetaDataMDX, self).__init__(None, **kwargs)
+ if not url:
+ raise SAMLError('URL for MDQ server not specified.')
+
self.url = url.rstrip('/')
if entity_transform:
self.entity_transform = entity_transform
else:
-
self.entity_transform = MetaDataMDX.sha1_entity_transform
+ self.cert = cert
+ self.security = security
+
+ # We assume that the MDQ server will return a single entity
+ # described by a single <EntityDescriptor> element. The protocol
+ # does allow multiple entities to be returned in an
+ # <EntitiesDescriptor> element but we will not currently support
+ # that use case since it is unlikely to leveraged for most
+ # flows.
+ self.node_name = "%s:%s" % (md.EntityDescriptor.c_namespace,
+ md.EntityDescriptor.c_tag)
+
def load(self, *args, **kwargs):
# Do nothing
pass
@@ -906,8 +926,17 @@ class MetadataStore(MetaData):
key = args[1]
_md = MetaDataLoader(self.attrc, args[1], **_args)
elif typ == "mdq":
- key = args[1]
- _md = MetaDataMDX(args[1])
+ if 'url' in kwargs:
+ key = kwargs['url']
+ url = kwargs['url']
+ cert = kwargs.get('cert', None)
+ security = self.security
+ entity_transform = kwargs.get('entity_transform', None)
+ _md = MetaDataMDX(url, security, cert, entity_transform)
+ else:
+ key = args[1]
+ url = args[1]
+ _md = MetaDataMDX(url)
else:
raise SAMLError("Unknown metadata type '%s'" % typ)
_md.load()