From 18b39735b774ea9d85372ea1d9047ea44e6e3404 Mon Sep 17 00:00:00 2001 From: example Date: Tue, 7 Oct 2025 12:32:31 +0200 Subject: [PATCH] initial commit --- attributemaps/__init__.py | 19 +++ gunicorn_config.py | 2 + internal_attributes.yaml | 51 ++++++++ plugins/attribute_policy.yaml | 176 +++++++++++++++++++++++++++ plugins/eduPersonEntitlement.yaml | 5 + plugins/eduPersonTargetedID.yaml | 7 ++ plugins/eduPersonUniqueId.yaml | 13 ++ plugins/saml2_backend.yaml | 97 +++++++++++++++ plugins/saml2_frontend.yaml | 112 +++++++++++++++++ plugins/schacPersonalUniqueCode.yaml | 10 ++ plugins/static_attributes.yaml | 9 ++ proxy_conf.yaml | 122 +++++++++++++++++++ 12 files changed, 623 insertions(+) create mode 100644 attributemaps/__init__.py create mode 100644 gunicorn_config.py create mode 100644 internal_attributes.yaml create mode 100644 plugins/attribute_policy.yaml create mode 100644 plugins/eduPersonEntitlement.yaml create mode 100644 plugins/eduPersonTargetedID.yaml create mode 100644 plugins/eduPersonUniqueId.yaml create mode 100644 plugins/saml2_backend.yaml create mode 100644 plugins/saml2_frontend.yaml create mode 100644 plugins/schacPersonalUniqueCode.yaml create mode 100644 plugins/static_attributes.yaml create mode 100644 proxy_conf.yaml diff --git a/attributemaps/__init__.py b/attributemaps/__init__.py new file mode 100644 index 0000000..8401625 --- /dev/null +++ b/attributemaps/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +from saml2.attributemaps.saml_uri import MAP + +__unilogin_custom_MAP = { + 'identifier': 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', + 'fro': { + 'urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.13': 'SAPemployeeNumber', + 'urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.14': 'PMidentNr', + 'urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.15': 'obfuscatedID', + }, + 'to': { + 'SAPemployeeNumber': 'urn:oid:2.16.840.1.113730.3.1.3', + 'PMidentNr': 'urn:oid:2.16.840.1.113730.3.1.3', + 'obfuscatedID': 'urn:oid:2.16.840.1.113730.3.1.3', + }, +} + +MAP['fro'].update(__unilogin_custom_MAP['fro']) +MAP['to'].update(__unilogin_custom_MAP['to']) diff --git a/gunicorn_config.py b/gunicorn_config.py new file mode 100644 index 0000000..4f8383f --- /dev/null +++ b/gunicorn_config.py @@ -0,0 +1,2 @@ +bind = "127.0.0.1:8088" +workers = 3 diff --git a/internal_attributes.yaml b/internal_attributes.yaml new file mode 100644 index 0000000..7e5c45c --- /dev/null +++ b/internal_attributes.yaml @@ -0,0 +1,51 @@ +attributes: + displayName: + saml: [displayName] + givenName: + saml: [givenName] + sn: + saml: [sn] + mail: + saml: [mail] + + cn: + saml: [cn] + uid: + saml: [uid] + + samlSubjectID: + saml: [subject-id] + samlPairwiseID: + saml: [pairwise-id] + + schacHomeOrganization: + saml: [schacHomeOrganization] + schacHomeOrganizationType: + saml: [schacHomeOrganizationType] + postalAddress: + saml: [postalAddress] + title: + saml: [title] + o: + saml: [o] + + eduPersonPrincipalName: + saml: [eduPersonPrincipalName] + eduPersonScopedAffiliation: + saml: [eduPersonScopedAffiliation] + eduPersonUniqueId: + saml: [eduPersonUniqueId] + + eduPersonTargetedID: + saml: [eduPersonTargetedID] + eduPersonEntitlement: + saml: [eduPersonEntitlement] + schacPersonalUniqueCode: + saml: [schacPersonalUniqueCode] + + SAPemployeeNumber: + saml: [SAPemployeeNumber] + PMidentNr: + saml: [PMidentNr] + obfuscatedID: + saml: [obfuscatedID] diff --git a/plugins/attribute_policy.yaml b/plugins/attribute_policy.yaml new file mode 100644 index 0000000..66c4025 --- /dev/null +++ b/plugins/attribute_policy.yaml @@ -0,0 +1,176 @@ +module: satosa.micro_services.attribute_policy.AttributePolicy +name: attributePolicy +config: + policies: + - id: REFEDSResearchAndScholarship + rules: + - type: EntityAttributeExactMatch + attributeName: "http://macedir.org/entity-category" + attributeValue: "http://refeds.org/category/research-and-scholarship" + allowed: + - eduPersonPrincipalName + - eduPersonTargetedID + - mail + - displayName + - givenName + - sn + - eduPersonScopedAffiliation + + - id: GeantEEADataProtectionCodeOfConduct + rules: + - type: EntityAttributeExactMatch + attributeName: "http://macedir.org/entity-category" + attributeValue: "http://www.geant.net/uri/dataprotection-code-of-conduct/v1" + allowed: + - displayName + - givenName + - sn + - mail + - eduPersonScopedAffiliation + - eduPersonPrincipalName + - eduPersonUniqueId + - eduPersonTargetedID + - schacPersonalUniqueCode + - schacHomeOrganization + + - id: MyAcacemicID + rules: + - type: EntityAttributeExactMatch + attributeName: "http://macedir.org/entity-category" + attributeValue: "https://myacademicid.org/entity-categories/esi" + allowed: + - schacPersonalUniqueCode + - eduPersonEntitlement + + - id: RegisteredByACOnetRequiredAttributes + rules: + - type: RegistrationAuthority + registrars: "http://eduid.at" + allowed: + - displayName + - givenName + - sn + - mail + - eduPersonScopedAffiliation + - eduPersonPrincipalName + - eduPersonUniqueId + - eduPersonTargetedID + - schacHomeOrganization + - eduPersonEntitlement + + - id: eduID.at-Demo-SP + rules: + - type: Requester + value: "https://test-sp.aco.net/shibboleth" + allowed: + - givenName + - sn + - displayName + - mail + - samlSubjectID + - samlPairwiseID + - eduPersonPrincipalName + - eduPersonScopedAffiliation + - eduPersonEntitlement + - eduPersonTargetedID + - schacHomeOrganization + - schacPersonalUniqueCode + + - id: brzportal + rules: + - type: Requester + value: "https://federation.portal.at/sp_metadata.xml" + - type: Requester + value: "https://federation2.portal.at/sp_metadata.xml" + allowed: + - eduPersonScopedAffiliation + - SAPemployeeNumber + - displayName + - sn + - givenName + - eduPersonTargetedID + - mail + - schacHomeOrganization + - cn + - eduPersonPrincipalName + + - id: mobility + rules: + - type: Requester + value: "https://mobility.uni-graz.at/mobility" + allowed: + - eduPersonScopedAffiliation + - cn + - displayName + - eduPersonPrincipalName + - mail + - o + - ou + - postalAddress + - title + - uid + - obfuscatedID + - eduPersonTargetedID + security: + force_authn: true + authn_context: [ "https://refeds.org/profile/mfa" ] + + - id: exam-extern + rules: + - type: Requester + value: "https://exam-extern.uni-graz.at/sso/module.php/saml/sp/metadata.php/exam" + allowed: + - eduPersonScopedAffiliation + - cn + - givenName + - sn + - mail + - uid + - eduPersonAffiliation + - eduPersonPrincipalName + - eduPersonTargetedID + - displayName + + - id: ubg-alma + rules: + - type: Requester + value: "https://obv-at-ubg.alma.exlibrisgroup.com/mng/login" + allowed: + - eduPersonScopedAffiliation + - schacHomeOrganization + - mail + - eduPersonPrincipalName + - eduPersonTargetedID + - givenName + - displayName + - sn + - PMidentNr + + - id: harica + rules: + - type: Requester + value: "https://exam-extern.uni-graz.at/sso/module.php/saml/sp/metadata.php/exam" + allowed: + - eduPersonScopedAffiliation + - cn + - givenName + - sn + - mail + - uid + - eduPersonAffiliation + - eduPersonPrincipalName + - eduPersonTargetedID + - displayName + + - id: default + rules: + - type: ANY + allowed: + - eduPersonScopedAffiliation + - schacHomeOrganization + - mail + - eduPersonPrincipalName + - eduPersonTargetedID + - givenName + - displayName + - sn diff --git a/plugins/eduPersonEntitlement.yaml b/plugins/eduPersonEntitlement.yaml new file mode 100644 index 0000000..a95cb9e --- /dev/null +++ b/plugins/eduPersonEntitlement.yaml @@ -0,0 +1,5 @@ +module: satosa.micro_services.eduid_entitlement.EduIDEntitlement +name: eduPersonEntitlement +config: + attribute: eduPersonEntitlement + source: eduPersonScopedAffiliation diff --git a/plugins/eduPersonTargetedID.yaml b/plugins/eduPersonTargetedID.yaml new file mode 100644 index 0000000..3226b60 --- /dev/null +++ b/plugins/eduPersonTargetedID.yaml @@ -0,0 +1,7 @@ +module: satosa.micro_services.shibboleth_computeid.ShibbolethComputedID +name: shibComputedID +config: + attribute: eduPersonTargetedID + source: uid + hash_algo: sha1 + salt: *** diff --git a/plugins/eduPersonUniqueId.yaml b/plugins/eduPersonUniqueId.yaml new file mode 100644 index 0000000..55af19c --- /dev/null +++ b/plugins/eduPersonUniqueId.yaml @@ -0,0 +1,13 @@ +module: satosa.micro_services.attribute_processor.AttributeProcessor +name: eduPersonUniqueIdProcessor +config: + process: + - attribute: eduPersonUniqueId + processors: + - name: HashProcessor + module: satosa.micro_services.processors.hash_processor + hash_alg: sha256 + salt: eduPersonUniqueId + - name: ScopeProcessor + module: satosa.micro_services.processors.scope_processor + scope: uni-graz.at diff --git a/plugins/saml2_backend.yaml b/plugins/saml2_backend.yaml new file mode 100644 index 0000000..1fc3dde --- /dev/null +++ b/plugins/saml2_backend.yaml @@ -0,0 +1,97 @@ +module: satosa.backends.saml2.SAMLBackend +name: idp +config: + entityid_endpoint: true + mirror_force_authn: true + memorize_idp: no + use_memorized_idp_when_force_authn: no + send_requester_id: true + enable_metadata_reload: false + acs_selection_strategy: use_first_acs + + sp_config: + name: SATOSA Proxy SP (Backend) + description: zididp.uni-graz.at + key_file: ssl/sp.key + cert_file: ssl/sp.crt + organization: + display_name: zididp.uni-graz.at + name: SATOSA Proxy SP (Backend) + url: "https://zididp.uni-graz.at" + + metadata: + local: + - metadata/login.uni-graz.at.xml +# - metadata/devlogin.uni-graz.at.xml + + entityid: //proxy_saml2_backend.xml + accepted_time_diff: 60 + attribute_map_dir: attributemaps + + service: + sp: + authn_requests_signed: true + want_response_signed: true + allow_unsolicited: true + endpoints: + assertion_consumer_service: + - [ //acs/post, urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST ] + + name_id_format: + - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + - urn:oasis:names:tc:SAML:2.0:nameid-format:transient + - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + name_id_policy_format: urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + requested_attributes: + - friendly_name: givenName + name: urn:oid:2.5.4.42 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: sn + name: urn:oid:2.5.4.4 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: mail + name: urn:oid:0.9.2342.19200300.100.1.3 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: displayName + name: urn:oid:2.16.840.1.113730.3.1.241 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: eduPersonPrincipalName + name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: eduPersonUniqueId + name: urn:oid:1.3.6.1.4.1.5923.1.1.1.13 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: eduPersonScopedAffiliation + name: urn:oid:1.3.6.1.4.1.5923.1.1.1.9 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: schacPersonalUniqueCode + name: urn:oid:1.3.6.1.4.1.25178.1.2.14 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: SAPemployeeNumber + name: urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.13 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: PKemployeeNumber + name: urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.14 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: UGOemployeeNumber + name: urn:oid:1.3.6.1.4.1.56980.4950.4.16.143050.6.15 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: uid + name: urn:oid:0.9.2342.19200300.100.1.1 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + + - friendly_name: cn + name: urn:oid:2.5.4.3 + name_format: urn:oasis:names:tc:SAML:2.0:attrname-format:uri diff --git a/plugins/saml2_frontend.yaml b/plugins/saml2_frontend.yaml new file mode 100644 index 0000000..645ba15 --- /dev/null +++ b/plugins/saml2_frontend.yaml @@ -0,0 +1,112 @@ +module: satosa.frontends.saml2.SAMLUnsolicitedFrontend +name: idpfrontend +config: + acr_mapping: + "": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" + + unsolicited: + endpoint: profile/SAML2/Unsolicited/SSO + allowed_relay_state_urls: + "https://federation.portal.at/sp_metadata.xml": + - https://fedsapuni.portal.at/sap/bc/ui2/flp + "https://federation2.portal.at/sp_metadata.xml": + - https://fedsapuni2.portal.at/sap/bc/ui2/flp + + endpoints: + single_sign_on_service: + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST': profile/SAML2/POST/SSO + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect': profile/SAML2/Redirect/SSO + + entityid_endpoint: true + enable_metadata_reload: true + + idp_config: + organization: + display_name: + - [ University of Graz, en ] + - [ Universität Graz, de ] + name: + - [ University of Graz, en ] + - [ Universität Graz, de ] + url: + - [ 'https://www.uni-graz.at/en/', en ] + - [ 'https://www.uni-graz.at/de/', de ] + contact_person: + - contact_type: technical + given_name: Technical + email_address: 'mailto:shibboleth@uni-graz.at' + - contact_type: support + given_name: IT-Support + email_address: 'mailto:servicedesk@uni-graz.at' + - contact_type: other + given_name: Security Response Team + email_address: 'mailto:security@uni-graz.at' + extension_attributes: + 'xmlns:remd': 'http://refeds.org/metadata' + 'remd:contactType': 'http://refeds.org/metadata/contactType/security' + assurance_certification: + - https://refeds.org/sirtfi + - https://refeds.org/sirtfi2 + entity_category_support: + - http://www.geant.net/uri/dataprotection-code-of-conduct/v1 + - http://refeds.org/category/research-and-scholarship + - https://myacademicid.org/entity-categories/esi + + key_file: ssl/idp.key + cert_file: ssl/idp.crt + encryption_keypairs: + - key_file: ssl/idp-encryption.key + cert_file: ssl/idp-encryption.crt + metadata: + local: + - metadata/federation.portal.at.xml + - metadata/federation2.portal.at.xml + - metadata/exam-extern.uni-graz.at.xml + - metadata/mobility.uni-graz.at.xml + - metadata/ubgalma-metadata.xml + mdq: + - url: http://127.0.0.1:8087 + freshness_period: P0Y0M0DT1H0M0S + disable_ssl_certificate_validation: True + + entityid: /idp/shibboleth + accepted_time_diff: 60 + attribute_map_dir: attributemaps + + service: + idp: + endpoints: + single_sign_on_service: [] + name: SATOSA Proxy IdP (Frontend) + ui_info: + display_name: + - { text: University of Graz, lang: en } + - { text: Universität Graz, lang: de } + keywords: + - { text: [ 'uni+graz', 'kfu+graz', 'kfug' ], lang: en } + - { text: [ 'uni+graz', 'kfu+graz', 'kfug' ], lang: de } + logo: + - { text: 'https://zididp.uni-graz.at/logo_4c.png', width: '250', height: '213' } + - { text: 'https://zididp.uni-graz.at/favicon.ico', width: '16', height: '16' } + scope: + - uni-graz.at + - edu.uni-graz.at + - ubpublic.uni-graz.at + - public.ad.uni-graz.at + name_id_format: + - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + - urn:oasis:names:tc:SAML:2.0:nameid-format:transient + policy: + default: + name_qualifier: https://zididp.uni-graz.at/idp/shibboleth + fail_on_missing_requested: false + lifetime: {minutes: 15} + name_form: urn:oasis:names:tc:SAML:2.0:attrname-format:uri + sign_response: true + sign_assertion: false + encrypt_assertion: false + encrypted_advice_attributes: false + attribute_restrictions: null + signing_algorithm: http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 + digest_algorithm: http://www.w3.org/2001/04/xmlenc#sha256 diff --git a/plugins/schacPersonalUniqueCode.yaml b/plugins/schacPersonalUniqueCode.yaml new file mode 100644 index 0000000..c1cfb03 --- /dev/null +++ b/plugins/schacPersonalUniqueCode.yaml @@ -0,0 +1,10 @@ +module: satosa.micro_services.attribute_processor.AttributeProcessor +name: schacPersonalUniqueCodeProcessor +config: + process: + - attribute: schacPersonalUniqueCode + processors: + - name: RegexSubProcessor + module: satosa.micro_services.processors.regex_sub_processor + regex_sub_match_pattern: ([0-9]{7,8}) + regex_sub_replace_pattern: urn:schac:personalUniqueCode:int:esi:at:\1 diff --git a/plugins/static_attributes.yaml b/plugins/static_attributes.yaml new file mode 100644 index 0000000..ca99dac --- /dev/null +++ b/plugins/static_attributes.yaml @@ -0,0 +1,9 @@ +module: satosa.micro_services.attribute_modifications.AddStaticAttributes +name: AddAttributes +config: + static_attributes: + schacHomeOrganization: uni-graz.at + schacHomeOrganizationType: urn:schac:homeOrganizationType:int:university + postalAddress: Universitätsplatz 3, 8010 Graz, Austria + title: " " + o: KFUG diff --git a/proxy_conf.yaml b/proxy_conf.yaml new file mode 100644 index 0000000..023e354 --- /dev/null +++ b/proxy_conf.yaml @@ -0,0 +1,122 @@ +BASE: https://zididp.uni-graz.at + +COOKIE_STATE_NAME: "SATOSA_STATE" +CONTEXT_STATE_DELETE: yes +STATE_ENCRYPTION_KEY: "***" + +cookies_samesite_compat: + - ["SATOSA_STATE", "SATOSA_STATE_LEGACY"] + +INTERNAL_ATTRIBUTES: "internal_attributes.yaml" + +BACKEND_MODULES: + - "plugins/saml2_backend.yaml" + +FRONTEND_MODULES: + - "plugins/saml2_frontend.yaml" + +MICRO_SERVICES: + - "plugins/static_attributes.yaml" + - "plugins/eduPersonTargetedID.yaml" + - "plugins/eduPersonEntitlement.yaml" + - "plugins/eduPersonUniqueId.yaml" + - "plugins/schacPersonalUniqueCode.yaml" + - "plugins/attribute_policy.yaml" + +LOGGING: + version: 1 + formatters: + debug: + format: "[%(asctime)s] [%(levelname)s] %(filename)s:%(lineno)d [%(name)s.%(funcName)s] %(message)s" + simple: + format: "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s" + handlers: + stdout: + class: logging.StreamHandler + stream: "ext://sys.stdout" + level: DEBUG + formatter: debug + syslog: + class: logging.handlers.SysLogHandler + address: "/dev/log" + level: DEBUG + formatter: simple + satosa_debug_file: + class: logging.handlers.RotatingFileHandler + filename: logs/satosa-debug.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 1 + level: DEBUG + formatter: debug + satosa_info_file: + class: logging.handlers.RotatingFileHandler + filename: logs/satosa-info.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: INFO + formatter: simple + satosa_warn_file: + class: logging.handlers.RotatingFileHandler + filename: logs/satosa-warn.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: WARN + formatter: simple + satosa_error_file: + class: logging.handlers.RotatingFileHandler + filename: logs/satosa-error.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: ERROR + formatter: simple + + info_file: + class: logging.handlers.RotatingFileHandler + filename: logs/info.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: INFO + formatter: simple + warn_file: + class: logging.handlers.RotatingFileHandler + filename: logs/warn.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: WARN + formatter: simple + error_file: + class: logging.handlers.RotatingFileHandler + filename: logs/error.log + encoding: utf8 + maxBytes: 1048576 # 1MB + backupCount: 10 + level: ERROR + formatter: simple + loggers: + satosa: + level: DEBUG + handlers: + - satosa_debug_file + - satosa_info_file + - satosa_warn_file + - satosa_error_file + saml2: + level: WARN + handlers: + - info_file + - warn_file + - error_file + oidcendpoint: + level: WARN + pyop: + level: WARN + oic: + level: WARN + root: + level: WARN