SAML 2.0 Via Authentik PHP/XML Error
Describe the bug Attempting to authenticate via SAML using Authentik as a provider results in an error after authenticating with Authentik (i.e. the error is in the PartDB stack somewhere).
It seems to be an issue with the PartDB stack decoding the SAML XML response.
To Reproduce Steps to reproduce the behavior:
- Set up PartDB Server
- Set up Authentik Server (with workers, etc.)
- Set up SAML 2.0 provider on Authentik
- Set up SAML on PartDB
- Attempt to authorise
- Successfuly authorise on authentik, but receive "An authentication exception occurred." on part DB Web UI
- Investigate PartDB docker logs
- See errors e.g.
php.ERROR: Warning: DOMDocument::loadXML(): Namespace prefix ds on Transform is not defined in Entity, line: 8 {"exception":"[object] (ErrorException(code: 0): Warning: DOMDocument::loadXML(): Namespace prefix ds on Transform is not defined in Entity, line: 8 at /var/www/html/vendor/onelogin/php-saml/src/Saml2/Utils.php:88)and similar for various namespace prefixes (ds,saml) - Investigate SAML conversation using browser, confirm that many XML tags are named e.g.
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
Expected behavior PartDB should accept SAML XML data and authenticate user
Screenshots
Server Side
- Part-DB Version: Docker (
:latest) - PHP Version: Docker default
- Database Server: mysql (docker
:8.0) - SAML provider: Authentik (also on docker)
Desktop (please complete the following information):
- OS: Windows
- Browser Firefox
- Version 143.0.3
Additional context
The relevant errors are in the form (domain deliberately obfuscated):
[2025-10-03T13:48:28.802950+00:00] php.ERROR: Warning: DOMDocument::loadXML(): Namespace prefix saml on AttributeValue is not defined in Entity, line: 60 {"exception":"[object] (ErrorException(code: 0): Warning: DOMDocument::loadXML(): Namespace prefix saml on AttributeValue is not defined in Entity, line: 60 at /var/www/html/vendor/onelogin/php-saml/src/Saml2/Utils.php:88)
[stacktrace]
#0 /var/www/html/vendor/onelogin/php-saml/src/Saml2/Response.php(1168): OneLogin\\Saml2\\Utils::loadXML()
#1 /var/www/html/vendor/onelogin/php-saml/src/Saml2/Response.php(119): OneLogin\\Saml2\\Response->decryptAssertion()
#2 /var/www/html/vendor/onelogin/php-saml/src/Saml2/Auth.php(233): OneLogin\\Saml2\\Response->__construct()
#3 /var/www/html/vendor/nbgrp/onelogin-saml-bundle/src/Security/Http/Authenticator/SamlAuthenticator.php(134): OneLogin\\Saml2\\Auth->processResponse()
#4 /var/www/html/vendor/nbgrp/onelogin-saml-bundle/src/Security/Http/Authenticator/SamlAuthenticator.php(87): Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator->processResponse()
#5 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(185): Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator->authenticate()
#6 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(167): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->executeAuthenticator()
#7 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(149): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->executeAuthenticators()
#8 /var/www/html/vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php(38): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->authenticateRequest()
#9 /var/www/html/vendor/symfony/security-http/Firewall/AbstractListener.php(26): Symfony\\Component\\Security\\Http\\Firewall\\AuthenticatorManagerListener->authenticate()
#10 /var/www/html/vendor/symfony/security-bundle/Security/LazyFirewallContext.php(61): Symfony\\Component\\Security\\Http\\Firewall\\AbstractListener->__invoke()
#11 /var/www/html/vendor/symfony/security-http/Firewall.php(126): Symfony\\Bundle\\SecurityBundle\\Security\\LazyFirewallContext->__invoke()
#12 /var/www/html/vendor/symfony/security-http/Firewall.php(92): Symfony\\Component\\Security\\Http\\Firewall->callListeners()
#13 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(246): Symfony\\Component\\Security\\Http\\Firewall->onKernelRequest()
#14 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(206): Symfony\\Component\\EventDispatcher\\EventDispatcher::{closure:Symfony\\Component\\EventDispatcher\\EventDispatcher::optimizeListeners():241}()
#15 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\\Component\\EventDispatcher\\EventDispatcher->callListeners()
#16 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(159): Symfony\\Component\\EventDispatcher\\EventDispatcher->dispatch()
#17 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw()
#18 /var/www/html/vendor/symfony/http-kernel/Kernel.php(182): Symfony\\Component\\HttpKernel\\HttpKernel->handle()
#19 /var/www/html/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php(35): Symfony\\Component\\HttpKernel\\Kernel->handle()
#20 /var/www/html/vendor/autoload_runtime.php(29): Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner->run()
#21 /var/www/html/public/index.php(5): require_once()
#22 {main}
"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.806261+00:00] app.ERROR: Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd [] {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.806334+00:00] security.INFO: Authenticator failed. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException(code: 0): Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd at /var/www/html/vendor/nbgrp/onelogin-saml-bundle/src/Security/Http/Authenticator/SamlAuthenticator.php:93)
[stacktrace]
#0 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(185): Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator->authenticate()
#1 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(167): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->executeAuthenticator()
#2 /var/www/html/vendor/symfony/security-http/Authentication/AuthenticatorManager.php(149): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->executeAuthenticators()
#3 /var/www/html/vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php(38): Symfony\\Component\\Security\\Http\\Authentication\\AuthenticatorManager->authenticateRequest()
#4 /var/www/html/vendor/symfony/security-http/Firewall/AbstractListener.php(26): Symfony\\Component\\Security\\Http\\Firewall\\AuthenticatorManagerListener->authenticate()
#5 /var/www/html/vendor/symfony/security-bundle/Security/LazyFirewallContext.php(61): Symfony\\Component\\Security\\Http\\Firewall\\AbstractListener->__invoke()
#6 /var/www/html/vendor/symfony/security-http/Firewall.php(126): Symfony\\Bundle\\SecurityBundle\\Security\\LazyFirewallContext->__invoke()
#7 /var/www/html/vendor/symfony/security-http/Firewall.php(92): Symfony\\Component\\Security\\Http\\Firewall->callListeners()
#8 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(246): Symfony\\Component\\Security\\Http\\Firewall->onKernelRequest()
#9 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(206): Symfony\\Component\\EventDispatcher\\EventDispatcher::{closure:Symfony\\Component\\EventDispatcher\\EventDispatcher::optimizeListeners():241}()
#10 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\\Component\\EventDispatcher\\EventDispatcher->callListeners()
#11 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(159): Symfony\\Component\\EventDispatcher\\EventDispatcher->dispatch()
#12 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw()
#13 /var/www/html/vendor/symfony/http-kernel/Kernel.php(182): Symfony\\Component\\HttpKernel\\HttpKernel->handle()
#14 /var/www/html/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php(35): Symfony\\Component\\HttpKernel\\Kernel->handle()
#15 /var/www/html/vendor/autoload_runtime.php(29): Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner->run()
#16 /var/www/html/public/index.php(5): require_once('...')
#17 {main}
","authenticator":"Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.806392+00:00] security.DEBUG: Authentication failure, redirect triggered. {"failure_path":"login"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.806618+00:00] security.DEBUG: The "Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator" authenticator set the failure response. {"authenticator":"Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.807260+00:00] security.DEBUG: Clearing remember-me cookie. {"name":"REMEMBERME"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
[2025-10-03T13:48:28.807306+00:00] security.DEBUG: The "Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"Nbgrp\\OneloginSamlBundle\\Security\\Http\\Authenticator\\SamlAuthenticator"} {"token":null,"url":"/saml/acs","ip":"172.16.1.37","http_method":"POST","server":"partdb.domain.invalid","referrer":null}
This looks like this is either an issue with the response produced by Authentik or an issue in the php-saml library. As I do not know much about SAML, I will probably not be able to fix this issue.
I will try to implement OIDC as authentication method in the future.