diff --git a/app.py b/app.py
new file mode 100644
index 0000000..ce58ada
--- /dev/null
+++ b/app.py
@@ -0,0 +1,545 @@
+# from flask import Flask, request, redirect, session, render_template, url_for, make_response
+# from flask_cors import CORS
+# from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT, saml
+# from saml2.config import Config as Saml2Config
+# from saml2.client import Saml2Client
+# from saml2.saml import NameID
+# import logging
+# import secrets
+# import base64
+# import zlib
+# import xmltodict
+# import json
+# from urllib.parse import urlparse, parse_qs, quote
+# from cryptography.hazmat.primitives import hashes
+# from cryptography.hazmat.primitives.asymmetric import padding
+# from cryptography.hazmat.primitives import serialization
+# from lxml import etree
+
+# app = Flask(__name__)
+# app.secret_key = secrets.token_hex(16)
+# CORS(app)
+
+# logging.basicConfig(level=logging.INFO)
+
+# # Load configuration
+# with open('config.json') as config_file:
+# config_data = json.load(config_file)
+
+# # Temporary storage for SAML data
+# saml_storage = {
+# 'saml_request_id': '',
+# 'saml_request': '',
+# 'decoded_saml_request': ''
+# }
+
+# def saml_client():
+# config = Saml2Config()
+# config.load({
+# 'entityid': config_data['entityid'],
+# 'service': {
+# 'sp': {
+# 'name': 'SAML SP',
+# 'endpoints': {
+# 'assertion_consumer_service': [
+# (config_data['acs_url'], BINDING_HTTP_POST),
+# ],
+# 'single_logout_service': [
+# (config_data['sp_slo_url'], BINDING_HTTP_REDIRECT),
+# (config_data['sp_slo_url'], BINDING_HTTP_POST),
+# ],
+# },
+# 'required_attributes': config_data['required_attributes'],
+# 'optional_attributes': config_data['optional_attributes'],
+# 'authn_requests_signed': config_data['authn_requests_signed'],
+# 'want_assertions_signed': config_data['want_assertions_signed'],
+# 'want_response_signed': config_data['want_response_signed'],
+# 'return_addresses': [
+# config_data['sp_slo_url'],
+# config_data['idp_slo_url']
+# ],
+# },
+# },
+# 'metadata': {
+# 'local': [config_data['idp_metadata_file']],
+# },
+# 'key_file': config_data['key_file'],
+# 'cert_file': config_data['cert_file'],
+# 'allow_unknown_attributes': config_data['allow_unknown_attributes'],
+# 'debug': config_data['debug'],
+# })
+# return Saml2Client(config)
+
+
+# def pretty_print_xml(xml_string):
+# try:
+# xml_dict = xmltodict.parse(xml_string)
+# return xmltodict.unparse(xml_dict, pretty=True)
+# except Exception as e:
+# logging.error(f"Error parsing XML: {e}")
+# return xml_string
+
+# def sign_logout_request(logout_request, key_file):
+# with open(key_file, 'rb') as key_file_data:
+# private_key = serialization.load_pem_private_key(
+# key_file_data.read(),
+# password=None
+# )
+
+# # Parse the XML
+# root = etree.fromstring(logout_request.encode('utf-8'))
+
+# # Generate a digest of the entire XML string
+# digest = hashes.Hash(hashes.SHA1())
+# digest.update(logout_request.encode('utf-8'))
+# digest_value = digest.finalize()
+
+# # Sign the digest
+# signature = private_key.sign(
+# digest_value,
+# padding.PKCS1v15(),
+# hashes.SHA1()
+# )
+
+# # Create the Signature element
+# signature_value = base64.b64encode(signature).decode('utf-8')
+# signature_element = etree.Element('{http://www.w3.org/2000/09/xmldsig#}SignatureValue')
+# signature_element.text = signature_value
+
+# # Append the Signature element to the XML
+# root.append(signature_element)
+
+# # Convert the XML back to a string
+# signed_xml_string = etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='UTF-8').decode('utf-8')
+
+# return signed_xml_string
+
+# @app.route('/')
+# def index():
+# saml_request = saml_storage['saml_request']
+# decoded_saml_request = saml_storage['decoded_saml_request']
+# return render_template('index.html', saml_request=saml_request, decoded_saml_request=decoded_saml_request)
+
+# @app.route('/generate_saml_request', methods=['POST'])
+# def generate_saml_request():
+# client = saml_client()
+# reqid, info = client.prepare_for_authenticate()
+# location_header = dict(info['headers'])['Location']
+# parsed_url = urlparse(location_header)
+# saml_request = parse_qs(parsed_url.query)['SAMLRequest'][0]
+
+# # Decode and decompress SAML Request
+# decoded_saml_request = base64.b64decode(saml_request)
+# decompressed_saml_request = zlib.decompress(decoded_saml_request, -15).decode('utf-8')
+# pretty_saml_request = pretty_print_xml(decompressed_saml_request)
+
+# # Store in temporary storage
+# saml_storage['saml_request_id'] = reqid
+# saml_storage['saml_request'] = saml_request
+# saml_storage['decoded_saml_request'] = pretty_saml_request
+
+# return redirect('/')
+
+# @app.route('/sso', methods=['POST'])
+# def sso():
+# saml_request = request.form['saml_request']
+# encoded_saml_request = quote(saml_request) # Ensure the SAML request is URL encoded
+# redirect_url = f"{config_data['redirect_url']}?SAMLRequest={encoded_saml_request}"
+# return redirect(redirect_url)
+
+# @app.route('/acs', methods=['POST'])
+# def acs():
+# client = saml_client()
+# saml_response = request.form['SAMLResponse']
+# try:
+# outstanding = {saml_storage['saml_request_id']: 'example'}
+# authn_response = client.parse_authn_request_response(
+# saml_response, BINDING_HTTP_POST, outstanding=outstanding
+# )
+# session['user_info'] = authn_response.get_identity()
+
+# # Extract session_index from AuthnStatement
+# session_index = None
+# for statement in authn_response.assertion.authn_statement:
+# session_index = statement.session_index
+# if session_index:
+# break
+
+# if not session_index:
+# raise ValueError("No session index found in AuthnStatement")
+
+# # Store name_id and session_index as strings
+# session['name_id'] = str(authn_response.name_id)
+# session['session_index'] = session_index
+
+# # Decode SAML Response
+# decoded_saml_response = base64.b64decode(saml_response).decode('utf-8')
+# pretty_saml_response = pretty_print_xml(decoded_saml_response)
+
+# logging.info("User successfully logged in")
+
+# return render_template('response.html', saml_response=saml_response, pretty_saml_response=pretty_saml_response, user_info=session['user_info'])
+# except Exception as e:
+# logging.error(f"Error processing SAML response: {e}")
+# return f"Error processing SAML response: {e}", 500
+
+# @app.route('/logout', methods=['POST'])
+# def logout():
+# client = saml_client()
+# session_index = session.get('session_index')
+# name_id_str = session.get('name_id')
+
+# if 'entityid' not in config_data:
+# logging.error("Missing 'entityid' in configuration data")
+# return redirect(url_for('index'))
+
+# issuer_entity_id = config_data['entityid']
+
+# if session_index and name_id_str:
+# logging.info(f"Initiating logout for session_index: {session_index}, name_id: {name_id_str}")
+# try:
+# name_id = NameID(text=name_id_str, format=saml.NAMEID_FORMAT_EMAILADDRESS)
+
+# # Prepare the logout request
+# logout_request_id, logout_request = client.create_logout_request(
+# name_id=name_id,
+# session_indexes=[session_index],
+# destination=config_data['idp_slo_url'],
+# issuer_entity_id=issuer_entity_id
+# )
+
+# logout_request_str = str(logout_request)
+# logging.info(f"Logout request before signing: {logout_request_str}")
+
+# # Sign the logout request using cryptography
+# signed_logout_request_str = sign_logout_request(logout_request_str, client.config.key_file)
+# logging.info(f"Signed LogoutRequest: {signed_logout_request_str}")
+
+# # Encode the SAML request (deflate + base64)
+# deflated_logout_request = zlib.compress(signed_logout_request_str.encode('utf-8'))[2:-4]
+# saml_request_encoded = base64.b64encode(deflated_logout_request).decode('utf-8')
+# logging.info(f"Deflated LogoutRequest: {deflated_logout_request}")
+# logging.info(f"Base64 Encoded SAMLRequest: {saml_request_encoded}")
+
+# # Ensure the SAML request is URL encoded
+# encoded_saml_request = quote(saml_request_encoded)
+# logging.info(f"URL Encoded SAMLRequest: {encoded_saml_request}")
+
+# # Formulate the logout URL
+# logout_url = f"{config_data['idp_slo_url']}?SAMLRequest={encoded_saml_request}"
+
+# # Clear the session and SAML storage
+# session.clear()
+# clear_saml_storage()
+
+# # Clear cookies
+# response = make_response(redirect(logout_url))
+# response.set_cookie('session', '', expires=0)
+# for key in request.cookies.keys():
+# response.set_cookie(key, '', expires=0)
+
+# logging.info("User successfully logged out")
+# return response
+# except Exception as e:
+# logging.error(f"Error creating logout request: {e}")
+# logging.error(f"Error details: {e.__class__.__name__}, {str(e)}")
+# return f"Error creating logout request: {e}", 500
+
+# # In case of missing session data, clear and redirect
+# session.clear()
+# clear_saml_storage()
+
+# # Clear cookies
+# response = make_response(redirect(url_for('index')))
+# response.set_cookie('session', '', expires=0)
+# for key in request.cookies.keys():
+# response.set_cookie(key, '', expires=0)
+
+# logging.info("Session and cookies cleared, redirected to index")
+# return response
+
+# @app.route('/slo', methods=['POST'])
+# def slo():
+# response = request.form.get('SAMLResponse')
+# if response:
+# try:
+# client = saml_client()
+# logout_response = client.parse_logout_request_response(
+# response, BINDING_HTTP_POST
+# )
+# if logout_response:
+# # Clear the session and redirect to index
+# session.clear()
+# clear_saml_storage()
+# logging.info("Single logout successful, session cleared")
+# return redirect(url_for('index'))
+# except Exception as e:
+# logging.error(f"Error processing SLO response: {e}")
+# return f"Error processing SLO response: {e}", 500
+
+# logging.error("Invalid SLO response")
+# return "Invalid SLO response", 400
+
+# def clear_saml_storage():
+# saml_storage['saml_request_id'] = ''
+# saml_storage['saml_request'] = ''
+# saml_storage['decoded_saml_request'] = ''
+
+# if __name__ == '__main__':
+# app.run(debug=True)
+
+
+from flask import Flask, request, redirect, session, render_template, url_for, make_response
+from flask_cors import CORS
+from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT, saml
+from saml2.config import Config as Saml2Config
+from saml2.client import Saml2Client
+from saml2.saml import NameID
+import logging
+import secrets
+import base64
+import zlib
+import xmltodict
+import json
+from urllib.parse import urlparse, parse_qs, quote
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives import serialization
+from lxml import etree
+
+app = Flask(__name__)
+app.secret_key = secrets.token_hex(16)
+CORS(app)
+
+logging.basicConfig(level=logging.INFO)
+
+# Load configuration
+with open('config.json') as config_file:
+ config_data = json.load(config_file)
+
+# Temporary storage for SAML data
+saml_storage = {
+ 'saml_request_id': '',
+ 'saml_request': '',
+ 'decoded_saml_request': ''
+}
+
+def saml_client():
+ config = Saml2Config()
+ config.load({
+ 'entityid': config_data['entityid'],
+ 'service': {
+ 'sp': {
+ 'name': 'SAML SP',
+ 'endpoints': {
+ 'assertion_consumer_service': [
+ (config_data['acs_url'], BINDING_HTTP_POST),
+ ],
+ 'single_logout_service': [
+ (config_data['sp_slo_url'], BINDING_HTTP_REDIRECT),
+ (config_data['sp_slo_url'], BINDING_HTTP_POST),
+ ],
+ },
+ 'required_attributes': config_data['required_attributes'],
+ 'optional_attributes': config_data['optional_attributes'],
+ 'authn_requests_signed': config_data['authn_requests_signed'],
+ 'want_assertions_signed': config_data['want_assertions_signed'],
+ 'want_response_signed': config_data['want_response_signed'],
+ 'return_addresses': [
+ config_data['sp_slo_url'],
+ config_data['idp_slo_url']
+ ],
+ },
+ },
+ 'metadata': {
+ 'local': [config_data['idp_metadata_file']],
+ },
+ 'key_file': config_data['key_file'],
+ 'cert_file': config_data['cert_file'],
+ 'allow_unknown_attributes': config_data['allow_unknown_attributes'],
+ 'debug': config_data['debug'],
+ })
+ return Saml2Client(config)
+
+def pretty_print_xml(xml_string):
+ try:
+ xml_dict = xmltodict.parse(xml_string)
+ return xmltodict.unparse(xml_dict, pretty=True)
+ except Exception as e:
+ logging.error(f"Error parsing XML: {e}")
+ return xml_string
+
+def sign_logout_request(logout_request, key_file):
+ with open(key_file, 'rb') as key_file_data:
+ private_key = serialization.load_pem_private_key(key_file_data.read(), password=None)
+
+ # Parse the XML
+ root = etree.fromstring(logout_request.encode('utf-8'))
+
+ # Generate a digest of the entire XML string
+ digest = hashes.Hash(hashes.SHA1())
+ digest.update(logout_request.encode('utf-8'))
+ digest_value = digest.finalize()
+
+ # Sign the digest
+ signature = private_key.sign(digest_value, padding.PKCS1v15(), hashes.SHA1())
+
+ # Create the Signature element
+ signature_value = base64.b64encode(signature).decode('utf-8')
+ signature_element = etree.Element('{http://www.w3.org/2000/09/xmldsig#}SignatureValue')
+ signature_element.text = signature_value
+
+ # Append the Signature element to the XML
+ root.append(signature_element)
+
+ # Convert the XML back to a string
+ signed_xml_string = etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='UTF-8').decode('utf-8')
+
+ return signed_xml_string
+
+@app.route('/')
+def index():
+ saml_request = saml_storage['saml_request']
+ decoded_saml_request = saml_storage['decoded_saml_request']
+ return render_template('index.html', saml_request=saml_request, decoded_saml_request=decoded_saml_request)
+
+@app.route('/generate_saml_request', methods=['POST'])
+def generate_saml_request():
+ client = saml_client()
+ reqid, info = client.prepare_for_authenticate()
+ location_header = dict(info['headers'])['Location']
+ parsed_url = urlparse(location_header)
+ saml_request = parse_qs(parsed_url.query)['SAMLRequest'][0]
+
+ # Decode and decompress SAML Request
+ decoded_saml_request = base64.b64decode(saml_request)
+ decompressed_saml_request = zlib.decompress(decoded_saml_request, -15).decode('utf-8')
+ pretty_saml_request = pretty_print_xml(decompressed_saml_request)
+
+ # Store in temporary storage
+ saml_storage['saml_request_id'] = reqid
+ saml_storage['saml_request'] = saml_request
+ saml_storage['decoded_saml_request'] = pretty_saml_request
+
+ return redirect('/')
+
+@app.route('/sso', methods=['POST'])
+def sso():
+ saml_request = request.form['saml_request']
+ encoded_saml_request = quote(saml_request) # Ensure the SAML request is URL encoded
+ redirect_url = f"{config_data['redirect_url']}?SAMLRequest={encoded_saml_request}"
+ return redirect(redirect_url)
+
+@app.route('/acs', methods=['POST'])
+def acs():
+ client = saml_client()
+ saml_response = request.form['SAMLResponse']
+ try:
+ outstanding = {saml_storage['saml_request_id']: 'example'}
+ authn_response = client.parse_authn_request_response(
+ saml_response, BINDING_HTTP_POST, outstanding=outstanding
+ )
+ session['user_info'] = authn_response.get_identity()
+
+ # Extract session_index from AuthnStatement
+ session_index = None
+ for statement in authn_response.assertion.authn_statement:
+ session_index = statement.session_index
+ if session_index:
+ break
+
+ if not session_index:
+ raise ValueError("No session index found in AuthnStatement")
+
+ # Store name_id and session_index as strings
+ session['name_id'] = str(authn_response.name_id)
+ session['session_index'] = session_index
+
+ # Decode SAML Response
+ decoded_saml_response = base64.b64decode(saml_response).decode('utf-8')
+ pretty_saml_response = pretty_print_xml(decoded_saml_response)
+
+ logging.info("User successfully logged in")
+
+ return render_template('response.html', saml_response=saml_response, pretty_saml_response=pretty_saml_response, user_info=session['user_info'])
+ except Exception as e:
+ logging.error(f"Error processing SAML response: {e}")
+ return f"Error processing SAML response: {e}", 500
+
+@app.route('/logout', methods=['POST'])
+def logout():
+ client = saml_client()
+ session_index = session.get('session_index')
+ name_id_str = session.get('name_id')
+
+ if not session_index or not name_id_str:
+ session.clear()
+ clear_saml_storage()
+ return redirect(url_for('index'))
+
+ try:
+ name_id = NameID(text=name_id_str, format=saml.NAMEID_FORMAT_EMAILADDRESS)
+
+ # Prepare the logout request
+ logout_request_id, logout_request = client.create_logout_request(
+ name_id=name_id,
+ session_indexes=[session_index],
+ destination=config_data['idp_slo_url'],
+ issuer_entity_id=config_data['entityid']
+ )
+
+ # Sign the logout request
+ signed_logout_request_str = sign_logout_request(str(logout_request), client.config.key_file)
+
+ # Encode the SAML request (deflate + base64)
+ deflated_logout_request = zlib.compress(signed_logout_request_str.encode('utf-8'))[2:-4]
+ saml_request_encoded = base64.b64encode(deflated_logout_request).decode('utf-8')
+
+ # Ensure the SAML request is URL encoded
+ encoded_saml_request = quote(saml_request_encoded)
+
+ # Formulate the logout URL
+ logout_url = f"{config_data['idp_slo_url']}?SAMLRequest={encoded_saml_request}"
+
+ # Clear the session and SAML storage
+ session.clear()
+ clear_saml_storage()
+
+ # Clear cookies
+ response = make_response(redirect(logout_url))
+ response.set_cookie('session', '', expires=0)
+ for key in request.cookies.keys():
+ response.set_cookie(key, '', expires=0)
+
+ logging.info("User successfully logged out")
+ return response
+ except Exception as e:
+ logging.error(f"Error creating logout request: {e}")
+ return f"Error creating logout request: {e}", 500
+
+@app.route('/slo', methods=['POST'])
+def slo():
+ response = request.form.get('SAMLResponse')
+ if not response:
+ return "Invalid SLO response", 400
+
+ try:
+ client = saml_client()
+ logout_response = client.parse_logout_request_response(response, BINDING_HTTP_POST)
+ if logout_response:
+ # Clear the session and redirect to index
+ session.clear()
+ clear_saml_storage()
+ logging.info("Single logout successful, session cleared")
+ return redirect(url_for('index'))
+ except Exception as e:
+ logging.error(f"Error processing SLO response: {e}")
+ return f"Error processing SLO response: {e}", 500
+
+def clear_saml_storage():
+ saml_storage['saml_request_id'] = ''
+ saml_storage['saml_request'] = ''
+ saml_storage['decoded_saml_request'] = ''
+
+if __name__ == '__main__':
+ app.run(debug=True)
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..0dce258
--- /dev/null
+++ b/config.json
@@ -0,0 +1,18 @@
+{
+ "entityid": "https://zitadel-test.sp/metadata",
+ "acs_url": "http://127.0.0.1:5000/acs",
+ "idp_slo_url": "https://my-instance-xtzfbc.zitadel.cloud/saml/v2/SLO",
+ "sp_slo_url": "http://127.0.0.1:5000/slo",
+ "redirect_url": "https://my-instance-xtzfbc.zitadel.cloud/saml/v2/SSO",
+ "idp_metadata_file": "idp_metadata.xml",
+ "key_file": "sp-key.pem",
+ "cert_file": "sp-cert.pem",
+ "xmlsec_binary": "/opt/homebrew/bin/xmlsec1",
+ "required_attributes": ["uid"],
+ "optional_attributes": ["mail"],
+ "authn_requests_signed": true,
+ "want_assertions_signed": true,
+ "want_response_signed": false,
+ "allow_unknown_attributes": true,
+ "debug": 1
+}
diff --git a/idp_metadata.xml b/idp_metadata.xml
new file mode 100644
index 0000000..2faad4b
--- /dev/null
+++ b/idp_metadata.xml
@@ -0,0 +1,2 @@
+
+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urn:oasis:names:tc:SAML:2.0:profiles:attribute:basicurn:oasis:names:tc:SAML:2.0:nameid-format:persistenthttps://my-instance-xtzfbc.zitadel.cloud/saml/v2/metadata IDP signingMIIFITCCAwmgAwIBAgIBUTANBgkqhkiG9w0BAQsFADAsMRAwDgYDVQQKEwdaSVRBREVMMRgwFgYDVQQDEw9aSVRBREVMIFNBTUwgQ0EwHhcNMjQwNTIwMTIxNjQzWhcNMjUwNTIwMTgxNjQzWjAyMRAwDgYDVQQKEwdaSVRBREVMMR4wHAYDVQQDExVaSVRBREVMIFNBTUwgcmVzcG9uc2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDaVZkfAG7xhg/rEkBMzvOI4asj49utf9oM/EzpLHs0EPPMB5CLEfKnUkd9YMkG9M7bhPI2ApQSOCnlpKIumUtA/7r8ft2v0pJjq8eQ/EIMCXaFQnt0YKK3E1BgTBSbrGvRRwgeSzy9vziDzEy3j9Vk/65vXNj9qHWRF7cUlAqa9/WP+atQIbCl/j4SiDO/6gCqIeoxK17agz5sIoxhYIs95QLmxlqKdSSe+ldZUVyMwP7HN3OoMa7LZzjCJsaMMHEZ2mIVPWxpDD9KDQahgVYtPgtXGXF8RSTzPJlJIXCplxel6RlsTcAaOU2uMse767Hj4iWis206AeTIKOE8sqvtq7avDYGuLWq7FR0oR/3JWnXeRKseyPeLWBe+ThzfU959yaopjYW58f7178QZ6WGUfkUgBE4WYiWMrntaKROYOa4lgrJLe0UXUT5V5X++5DVmN2Ai4qT7ZyJNP+cH9PzpBB3+sgns8k5TljPkEpuYp/8b0uTGkPUNx5cNBw7usxcK8IB2dbFkAVNiLeSJddJ1zhgcfcFfJ03qOnjtmwmPz7oLgHHT+INTISHnJt+QAzH797UFls7gzPR7UNjTzR0oa6iFaaQZbNPZfv6+OK7SyFzWF4tjzSxCP3nNx3NLrP0aLMcPIIAEEXCSdpLXwAMqzgO7WhHTuO5qLlpKKXEOkwIDAQABo0gwRjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUHOzVG4W7yv6Aqp1HwrfzLZurxRowDQYJKoZIhvcNAQELBQADggIBAGtVUkvatE2BIn9/W2EHgWJDjjsrJfB+6UklmgwsV/WxZTaK35qkDUIJrGDtpbcYRpILJLHKJ06KmuFh6ko4XbS7FGZj4rQNa85C0CAsCZBcSV+I0Hm6DYFuXfMdV7jEEZ8u8HUFPhAin2+kPgvqI1dpdzW9VGoiLNA3tfAWNoKD4O4OkrAaZASX2UToy/JLHBOKLHF/azi71yxwD2yb7zVZt3G+SecFn03/rKcz7sDGZ511Yba827RpJKkV7aJefdWZDbdemul5UCZnCsGyubtBNPmJ+qZXRLSQ0cDQ1NZZ3exWm9BpBKoPe4PPX+OdmP9LwzhFq8I+Dc4WIKAbaq2i7+dmftuPbAU+Cl1bn1kkdR3cnqh/Vs8VJdXaZJmdViIsZo6nm2Tv8uYya2hOPPy6I8DQyRGGlWUmwEik5CGaaFlujoOzq8dgnbmZFVamrB3o78uak3u0sSZ5Y1AAXTeQF94LxcXlD1fUuzzCywBslkeBYZE1kBt2NqdPAdB2CJ8CDycS30l3ebckXL9tOSjzsas0z4forcGcIbBhchXjU/acdYEMFt5w+I7Z74MvMAbKyMghidTdScfVpkxHgWO5p1t/r0fQQUOpfAIF71P3v5IZQdq4IbYIG0hgY0KkHvETm1rSUNLQf6pQV1+I/OTiyf0bjfHhDjRuwuGw4lRnurn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:profiles:attribute:basichttps://my-instance-xtzfbc.zitadel.cloud/saml/v2/metadata IDP signingMIIFITCCAwmgAwIBAgIBUTANBgkqhkiG9w0BAQsFADAsMRAwDgYDVQQKEwdaSVRBREVMMRgwFgYDVQQDEw9aSVRBREVMIFNBTUwgQ0EwHhcNMjQwNTIwMTIxNjQzWhcNMjUwNTIwMTgxNjQzWjAyMRAwDgYDVQQKEwdaSVRBREVMMR4wHAYDVQQDExVaSVRBREVMIFNBTUwgcmVzcG9uc2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDaVZkfAG7xhg/rEkBMzvOI4asj49utf9oM/EzpLHs0EPPMB5CLEfKnUkd9YMkG9M7bhPI2ApQSOCnlpKIumUtA/7r8ft2v0pJjq8eQ/EIMCXaFQnt0YKK3E1BgTBSbrGvRRwgeSzy9vziDzEy3j9Vk/65vXNj9qHWRF7cUlAqa9/WP+atQIbCl/j4SiDO/6gCqIeoxK17agz5sIoxhYIs95QLmxlqKdSSe+ldZUVyMwP7HN3OoMa7LZzjCJsaMMHEZ2mIVPWxpDD9KDQahgVYtPgtXGXF8RSTzPJlJIXCplxel6RlsTcAaOU2uMse767Hj4iWis206AeTIKOE8sqvtq7avDYGuLWq7FR0oR/3JWnXeRKseyPeLWBe+ThzfU959yaopjYW58f7178QZ6WGUfkUgBE4WYiWMrntaKROYOa4lgrJLe0UXUT5V5X++5DVmN2Ai4qT7ZyJNP+cH9PzpBB3+sgns8k5TljPkEpuYp/8b0uTGkPUNx5cNBw7usxcK8IB2dbFkAVNiLeSJddJ1zhgcfcFfJ03qOnjtmwmPz7oLgHHT+INTISHnJt+QAzH797UFls7gzPR7UNjTzR0oa6iFaaQZbNPZfv6+OK7SyFzWF4tjzSxCP3nNx3NLrP0aLMcPIIAEEXCSdpLXwAMqzgO7WhHTuO5qLlpKKXEOkwIDAQABo0gwRjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUHOzVG4W7yv6Aqp1HwrfzLZurxRowDQYJKoZIhvcNAQELBQADggIBAGtVUkvatE2BIn9/W2EHgWJDjjsrJfB+6UklmgwsV/WxZTaK35qkDUIJrGDtpbcYRpILJLHKJ06KmuFh6ko4XbS7FGZj4rQNa85C0CAsCZBcSV+I0Hm6DYFuXfMdV7jEEZ8u8HUFPhAin2+kPgvqI1dpdzW9VGoiLNA3tfAWNoKD4O4OkrAaZASX2UToy/JLHBOKLHF/azi71yxwD2yb7zVZt3G+SecFn03/rKcz7sDGZ511Yba827RpJKkV7aJefdWZDbdemul5UCZnCsGyubtBNPmJ+qZXRLSQ0cDQ1NZZ3exWm9BpBKoPe4PPX+OdmP9LwzhFq8I+Dc4WIKAbaq2i7+dmftuPbAU+Cl1bn1kkdR3cnqh/Vs8VJdXaZJmdViIsZo6nm2Tv8uYya2hOPPy6I8DQyRGGlWUmwEik5CGaaFlujoOzq8dgnbmZFVamrB3o78uak3u0sSZ5Y1AAXTeQF94LxcXlD1fUuzzCywBslkeBYZE1kBt2NqdPAdB2CJ8CDycS30l3ebckXL9tOSjzsas0z4forcGcIbBhchXjU/acdYEMFt5w+I7Z74MvMAbKyMghidTdScfVpkxHgWO5p1t/r0fQQUOpfAIF71P3v5IZQdq4IbYIG0hgY0KkHvETm1rSUNLQf6pQV1+I/OTiyf0bjfHhDjRuwuGw4lRn
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..84245c4
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,6 @@
+Flask==2.2.2
+Flask-CORS==3.0.10
+pysaml2==6.5.1
+xmltodict==0.12.0
+cryptography==41.0.0
+lxml==4.9.2
diff --git a/sp-cert.pem b/sp-cert.pem
new file mode 100644
index 0000000..ca743e4
--- /dev/null
+++ b/sp-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIUfITRQGueqcK1fkd3dbNuJGQ9WSowDQYJKoZIhvcNAQEL
+BQAwazELMAkGA1UEBhMCTEsxEjAQBgNVBAgMCVNyaSBMYW5rYTEQMA4GA1UEBwwH
+Q29sb21ibzEQMA4GA1UECgwHWklUQURFTDEkMCIGCSqGSIb3DQEJARYVZGFrc2hp
+dGhhQHppdGFkZWwuY29tMB4XDTI0MDUyMTA3MzUzNVoXDTI1MDUyMTA3MzUzNVow
+azELMAkGA1UEBhMCTEsxEjAQBgNVBAgMCVNyaSBMYW5rYTEQMA4GA1UEBwwHQ29s
+b21ibzEQMA4GA1UECgwHWklUQURFTDEkMCIGCSqGSIb3DQEJARYVZGFrc2hpdGhh
+QHppdGFkZWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlaOA
+bdE53gM2j/kBmy/UFCCjy8YsVyUUSx23CfXs0T4IQEZyRWrgCchxFBGN+rZF7ZZt
+oeV7u4vwlXqzCdLBftIpoMO/tvQ8wEe8pUFaldXOhRrEYbwUqpSQHF61kBf7Lqfb
+LBCw+v13BfKn05siHmTB/6k4EHEoIytyaOkcJk8e+DvW9m5zuB4LCA2iCrrUZ//M
+sPPDkZ8pkC+VfBkBkm36td93QjNvkXNghoKj8SmgGfP9/83/2LH0qIRhysC3R0kf
+T+ARtTZXkB4ooBnma52Pnxc4aVHMfaYRxCx+V/qzJK5j+Z05GuJQydrgXXsdIhD9
+S1yF5XuaJcxOYOtRlQIDAQABo1MwUTAdBgNVHQ4EFgQUAaW3LdD3frG3uiRQevwq
+NJYQ9WUwHwYDVR0jBBgwFoAUAaW3LdD3frG3uiRQevwqNJYQ9WUwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFSPTNAo26fNq6TMoZiMkvh/cfhEI
+t7ybc+mB5WbaJWx0E38TNtolnvKvgXDGDdOHClWHWfoe8eA0ZhZlndfsZ7Um6g4l
+W53m7X9L9sefwDYui8YIoKeRZ6ANokffIIajntYsmgWbwTQ04DFsxXk8t6mKIovW
+qw2OyEZMuGMwbJamknaJj2z8pxYP80dWrq/Roq5gEoCA0jNBCr+uIhhWfv5FkJ6t
+52Y3Xa1bkrtAIOVQptEo6ehK1a55x/v5arWkFydUVZGRzoucUsGd+O34c5VaGfuX
+F8d0Pr24mdiPsAwF0cVjgLH4SzH2xHtIs4iL9ymvSGhZhdmD1rsIlInkrQ==
+-----END CERTIFICATE-----
diff --git a/sp-csr.pem b/sp-csr.pem
new file mode 100644
index 0000000..c126b5d
--- /dev/null
+++ b/sp-csr.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICsDCCAZgCAQAwazELMAkGA1UEBhMCTEsxEjAQBgNVBAgMCVNyaSBMYW5rYTEQ
+MA4GA1UEBwwHQ29sb21ibzEQMA4GA1UECgwHWklUQURFTDEkMCIGCSqGSIb3DQEJ
+ARYVZGFrc2hpdGhhQHppdGFkZWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAlaOAbdE53gM2j/kBmy/UFCCjy8YsVyUUSx23CfXs0T4IQEZyRWrg
+CchxFBGN+rZF7ZZtoeV7u4vwlXqzCdLBftIpoMO/tvQ8wEe8pUFaldXOhRrEYbwU
+qpSQHF61kBf7LqfbLBCw+v13BfKn05siHmTB/6k4EHEoIytyaOkcJk8e+DvW9m5z
+uB4LCA2iCrrUZ//MsPPDkZ8pkC+VfBkBkm36td93QjNvkXNghoKj8SmgGfP9/83/
+2LH0qIRhysC3R0kfT+ARtTZXkB4ooBnma52Pnxc4aVHMfaYRxCx+V/qzJK5j+Z05
+GuJQydrgXXsdIhD9S1yF5XuaJcxOYOtRlQIDAQABoAAwDQYJKoZIhvcNAQELBQAD
+ggEBAE/Jxs1+RqO0DNGE0w4iQ5G1lY5mkn2kCzCEjjzjc6NoFQ5+qLNlmtEXf3ui
+GNUiPCbUVfLlxXElEdFCzj3J4xZxnex14W63eFrpY4RRcExmR9Du+Yra95hNE+8R
+kLVoLyPqCbbDS69p0j6XSd9uNqXWiahCSc3RBNmHetXTjgsY8qUcvoB2FsJ+KGQk
+T4bp1avu34VxnIfBqxR6GKqN3l3S6xofVNqXpAnOJVH10t9zwnaCmccfwOExKQZR
+Xv6q5agIIbuiP1esaWdpLa9vP0oRtWjwQLP8WaVMjNUJoPStOiSo/w3RNxB26j5l
+Dgw8NxIjv3db0FBkSPUsIOmy9io=
+-----END CERTIFICATE REQUEST-----
diff --git a/sp-key.pem b/sp-key.pem
new file mode 100644
index 0000000..e36c036
--- /dev/null
+++ b/sp-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVo4Bt0TneAzaP
++QGbL9QUIKPLxixXJRRLHbcJ9ezRPghARnJFauAJyHEUEY36tkXtlm2h5Xu7i/CV
+erMJ0sF+0imgw7+29DzAR7ylQVqV1c6FGsRhvBSqlJAcXrWQF/sup9ssELD6/XcF
+8qfTmyIeZMH/qTgQcSgjK3Jo6RwmTx74O9b2bnO4HgsIDaIKutRn/8yw88ORnymQ
+L5V8GQGSbfq133dCM2+Rc2CGgqPxKaAZ8/3/zf/YsfSohGHKwLdHSR9P4BG1NleQ
+HiigGeZrnY+fFzhpUcx9phHELH5X+rMkrmP5nTka4lDJ2uBdex0iEP1LXIXle5ol
+zE5g61GVAgMBAAECggEABXt78soPgP5RV/BrQ776jRHUq0KwXWSXrz7Z9dMp4R3d
+zVKnaiESlaX5DdKs07D5s+aaHEXdOCki4EWI3LgsUnpE5l9CajB3L1ZEtGTfrdpF
+AQrStuZeQ94O8sy95/19vIWPpp6Mu81ghUb3XId0NkF1YbZwV7RFoH0KUCSsqgyX
+fr2SCkA4clmY1yr2tXollGQQolhYGQ55mBN+kIH+OzTQ4RwWjUW10DHJCmqpc1Bh
+efuyhCn+0cPSXfyEu5WFcRTq+yEtp9HLsy6T419/5tWqY7QfQQZvXykyZxdfAPw/
+n6tTsFR1lFpLg8VkdJTFZmZrbsdrAiI444AvsHr4WwKBgQDMRJ3jiOLbbmqVHbvI
+aiTZBlwqldm5cCpsENr+One5atYkk/gRpy1GIsc8fJeFMr7u5WcKS8wUqxN1Er+s
+Vg0r7FJFXcfz1H0+IwvDU9o2CwmTbbK9TuscaBzoIaqVZOU1fW0qWdDOZ0hoL5JT
+jIQBKf2ofKJv8z0nMSFSUA4ywwKBgQC7iRSFymGxwFnvRXz4BQkEOgaixseu83mC
+5RD9puD4nisb8WrnRIdyuIxNCzKUL5aWeCjkJtgjDNcm0ykTpwTpjUVWMWh/WRmI
+ddEgoW1S9zuFksEwh5Q0C5+psdeGSkJ+RRNiSD0kjnKXZ/r43ZYDsfudsQy8uRU3
+sfL8FID0xwKBgF0QyirXvBwjo3XK9TpredxTNHzGh0sgmoNf7pazxsZ4sZY6wGQy
+mcMBp2qcjWBHbYxkglzDifjEtPm7EA8RqbCgXB90idxCrMk5qGtW8e17e+JqsWvk
+3+OyX7E3XYPxUyjau3j3MNZJYkjtm6prM91f50zzdAKzfOI1VSwugzmHAoGBALB2
+2NzcBvmfqgDAPkuTUVyszTm2GofBiwFkUoybzu2ix6XPkWx0y49joIGOm9VcwjJs
+du3Yr2Cr4HgkEm7vpmuuBySH8XCDgscpNdOikqCTC2sxIKBts0MV/PNM6STwE4mF
+riu5Fe+kKqfVrA8pUtO/UqibxQSAlDqIM8CH+qBZAoGBAJ1q8v7eQUfCtF1wP0Ob
+RrxlY7ys90SqB8hu6kETNeKiWHPFUq4ZSEihlRGJ7XIsF/2bowoWJj9hmtNPhJl9
+oUnEz2Y/73ToJlsxQUfdJyMBxb7Z4F2THZvNSVFH+TWdeTpEu0ujJFgCgXLw6liG
+tlOSUnVy2KoACyAhDEgFmhYU
+-----END PRIVATE KEY-----
diff --git a/sp_metadata.xml b/sp_metadata.xml
new file mode 100644
index 0000000..f9c910c
--- /dev/null
+++ b/sp_metadata.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ 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
+
+
+
+
+
+ urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
+
+
+