From 8c298b0fdecedb7c2f58fa9a50d5a8207b98d558 Mon Sep 17 00:00:00 2001
From: Martin van Es <martin@mrvanes.com>
Date: Thu, 11 Nov 2021 10:30:17 +0100
Subject: [PATCH] First commit

---
 .gitignore       |  7 ++++++
 README.md        | 11 +++++++++-
 mdsigner.py      | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 requirements.txt |  2 ++
 4 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 .gitignore
 create mode 100755 mdsigner.py
 create mode 100644 requirements.txt

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..83d0c5f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+# created by virtualenv automatically
+bin/
+lib/
+pyvenv.cfg
+meta.crt
+meta.key
+*.xml
diff --git a/README.md b/README.md
index 7b70569..b329800 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,12 @@
 # alternate-mdx
 
-Alternate MDX research project
\ No newline at end of file
+Alternate MDX research project
+
+## Usage
+- Create python virtualenv
+- Activate virtualenv (```. bin/activate```)
+- ```pip install -r requirements.txt```
+- Create (self-signed) metadata signing cert (```meta.crt/meta.key```)
+- Create output directory (```mkdir output```)
+- Download metadata file(s)
+- Run ```./mdsigner <metadata file(s)>```
\ No newline at end of file
diff --git a/mdsigner.py b/mdsigner.py
new file mode 100755
index 0000000..3755643
--- /dev/null
+++ b/mdsigner.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+import sys
+import copy
+from concurrent.futures import ThreadPoolExecutor
+
+from lxml import etree as ET
+from signxml import XMLSigner, XMLVerifier
+import hashlib
+# import traceback
+
+
+# Find all IdP's in edugain metadata
+idps = []
+success = 0
+failed = 0
+maxthreads = 8
+
+cert = open("meta.crt").read()
+key = open("meta.key").read()
+
+
+def sign(xml, name):
+    global success, failed, cert
+    # print("Signer")
+    try:
+        sha1 = hashlib.sha1()
+        sha1.update(name.encode('utf-8'))
+        sha1d = sha1.hexdigest()
+        signed = XMLSigner().sign(xml, key=key, cert=cert)
+        out = ET.tostring(signed, pretty_print=True).decode()
+        # XMLVerifier().verify(out, x509_cert=cert)
+        with open(f'output/{sha1d}.xml', 'w') as f:
+            f.write(out)
+        success += 1
+    except Exception as e:
+        print(name)
+        print(f"  {e}")
+        # traceback.print_exc()
+        failed += 1
+
+
+with ThreadPoolExecutor(max_workers=maxthreads) as executor:
+    for mdfile in sys.argv[1:]:
+        tree = ET.ElementTree(file=mdfile)
+        root = tree.getroot()
+        ns = copy.deepcopy(root.nsmap)
+        ns['xml'] = 'http://www.w3.org/XML/1998/namespace'
+
+        for idp in root.findall('md:EntityDescriptor', ns):
+            entityID = idp.attrib.get('entityID', 'none')
+            if entityID not in idps:
+                idps.append(entityID)
+                executor.submit(sign, idp, entityID)
+
+print(f"Succeeded: {success}")
+print(f"Failed: {failed}")
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..fa728d5
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+lxml
+signxml
-- 
GitLab