SuiteCRM 8.7.1 SAML Azure

Hi,

I am using SuiteCRM 8.7.1 (local hosting) and trying to configure SAML but not having success for the I believe the user mapping into SuiteCRM. I followed the below guide as well as the case below that:

https://docs.suitecrm.com/8.x/admin/configuration/saml/8.7.0-saml-configuration/

https://community.suitecrm.com/t/suitecrm-8-saml-azure-hslavich/91960

Authentication is fine at the Azure side with successful logins however at the SuiteCRM side I get the log-out screen. Referring to the guide it mentions a Auth.log but I did not find it. I adjusted the security log to show debugging where I get the following:

[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“main”,“authenticators”:2}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Access denied, the user is not fully authenticated; redirecting to authentication entry point. {“exception”:“[object] (Symfony\Component\Security\Core\Exception\AccessDeniedException(code: 403): Access Denied. at /var/www/suitecrm/vendor/symfony/security-http/Firewall/AccessListener.php:87)”}
[2025-01-09 22:55:25] security.DEBUG: Calling Authentication entry point. {“entry_point”:“[object] (App\Security\Saml\AppSamlAuthenticator: {})”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“main”,“authenticators”:2}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“main”,“authenticators”:2}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.INFO: Authenticator failed. {“exception”:“[object] (Symfony\Component\Security\Core\Exception\AuthenticationException(code: 0): Unable to extract public key at /var/www/suitecrm/vendor/nbgrp/onelogin-saml-bundle/src/Security/Http/Authenticator/SamlAuthenticator.php:93)”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authentication failure, redirect triggered. {“failure_path”:“logged-out”}
[2025-01-09 22:55:25] security.DEBUG: The “App\Security\Saml\AppSamlAuthenticator” authenticator set the failure response. {“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: The “App\Security\Saml\AppSamlAuthenticator” authenticator set the response. Any later authenticator will not be called {“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“logged_out”,“authenticators”:1}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“logged_out”,“authenticator”:“App\Security\AppJsonLoginAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“logged_out”,“authenticator”:“App\Security\AppJsonLoginAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“auth”,“authenticators”:1}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“auth”,“authenticator”:“App\Security\AppJsonLoginAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“auth”,“authenticator”:“App\Security\AppJsonLoginAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“main”,“authenticators”:2}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking for authenticator support. {“firewall_name”:“main”,“authenticators”:2}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“App\Security\Saml\AppSamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Checking support on authenticator. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}
[2025-01-09 22:55:25] security.DEBUG: Authenticator does not support the request. {“firewall_name”:“main”,“authenticator”:“Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator”}

Following the sequence of events there is an access denied but there are no mention of which user it is denying access for. My assumption here is that the username attribute map is not working correctly for the configuration in the .env. Below is my configuration summary:

AUTH_TYPE=saml
SAML_USERNAME_ATTRIBUTE=name
SAML_USE_ATTRIBUTE_FRIENDLY_NAME=true
SAML_IDP_ENTITY_ID=‘https://sts.windows.net/**********************/’
SAML_IDP_SSO_URL=‘https://login.microsoftonline.com/********************/saml2’
SAML_IDP_SLO_URL=‘https://login.microsoftonline.com/********************/saml2’
SAML_IDP_X509CERT=‘/etc/ssl/certs/idp.cer’
SAML_SP_ENTITY_ID=‘**********************’
SAML_SP_PRIVATE_KEY=‘/etc/ssl/private/scrm.key’
SAML_SP_CERT=‘/etc/ssl/certs/scrm.crt’
SAML_STRICT=‘’
SAML_DEBUG=true

Resquest options

SAML_NAME_ID_ENCRYPTED=false
SAML_AUTHN_REQUESTS_SIGNED=false
SAML_LOGOUT_REQUEST_SIGNED=false
SAML_LOGOUT_RESPONSE_SIGNED=false
SAML_SIGN_METADATA=false
SAML_WANT_MESSAGES_SIGNED=false
SAML_WANT_ASSERTIONS_ENCRYPTED=false
SAML_WANT_ASSERTIONS_SIGNED=true
SAML_WANT_NAME_ID=false
SAML_WANT_NAME_ID_ENCRYPTED=false
SAML_REQUESTED_AUTHN_CONTEXT=false
SAML_WANT_XML_VALIDATION=false
SAML_RELAX_DESTINATION_VALIDATION=false
SAML_DESTINATION_STRICTLY_MATCHES=false
SAML_ALLOW_REPEAT_ATTRIBUTE_NAME=false
SAML_REJECT_UNSOLICITED_RESPONSES_WITH_IN_RESPONSE_TO=false
SAML_LOWERCASE_URL_ENCODING=false

Compression

SAML_COMPRESS_REQUESTS=true
SAML_COMPRESS_RESPONSES=true

Contact information (this section was left default)

SAML_CONTACT_TECHNICAL_GIVEN_NAME=‘Tech User’
SAML_CONTACT_TECHNICAL_EMAIL_ADDRESS=‘techuser@example.com’
SAML_CONTACT_SUPPORT_GIVEN_NAME=‘Support User’
SAML_CONTACT_SUPPORT_EMAIL_ADDRESS=‘supportuser@example.com’
SAML_CONTACT_ADMINISTRATIVE_GIVEN_NAME=‘Administrative User’
SAML_CONTACT_ADMINISTRATIVE_EMAIL_ADDRESS=‘administrativeuser@example.com’
SAML_ORGANIZATION_NAME=‘Example’
SAML_ORGANIZATION_DISPLAY_NAME=‘Example’
SAML_ORGANIZATION_URL=‘http://example.com’

Azure Configuration (relevant users also assigned to enterprise application):
Identifier (Entity ID) https://crm.yourdomain.com
Reply URL (Assertion Consumer Service URL) https://crm.yourdomain.com/saml/acs
Sign on URL Optional
Relay State (Optional) Optional
Logout Url (Optional) Optional

I am a bit stuck as I have tried a few options in the .env file but no dice.
What am I missing in the configuration? Also any recommenctions for the .env is welcome, ie any options that is best practice.

Did a bit more work on this one. I did an upgrade from 8.6.1 to 8.7.1 so to rule out any issues as part of the upgrade I did a clean installation of 8.7.1. I also did all the configuration in the .env.local rather than the .env file.

In addition I also manually created the user to match the fields in EntraID and in SuiteCRM and made the field: external_auth_only=true. Still no dice with the login and still logs out immediatly. The prod.log has these in it now:
request.INFO: Matched route “index”. {“route”:“index”,“route_parameters”:{“_route”:“index”,“_stateless”:false,“_controller”:“App\Engine\Controller\IndexController::index”},“request_uri”:“https://crm.yourdomain.com/",“method”:"GET”}
request.INFO: Matched route “saml_login”. {“route”:“saml_login”,“route_parameters”:{“_route”:“saml_login”,“idp”:null,“_controller”:“Nbgrp\OneloginSamlBundle\Controller\Login”},“request_uri”:“https://crm.yourdomain.com/saml/login",“method”:"GET”}
request.INFO: Matched route “saml_acs”. {“route”:“saml_acs”,“route_parameters”:{“_route”:“saml_acs”,“idp”:null,“_controller”:“Nbgrp\OneloginSamlBundle\Controller\AssertionConsumerService”},“request_uri”:“https://crm.yourdomain.com/saml/acs",“method”:"POST”}
app.ERROR: Unable to extract public key
request.INFO: Matched route “logged-out”. {“route”:“logged-out”,“route_parameters”:{“_route”:“logged-out”,“_stateless”:false,“_controller”:“App\Engine\Controller\IndexController::loggedOut”},“request_uri”:“https://crm.yourdomain.com/logged-out",“method”:"GET”}
request.INFO: Matched route “nativeAuth”. {“route”:“nativeAuth”,“route_parameters”:{“_route”:“nativeAuth”,“_controller”:“App\Engine\Controller\IndexController::nativeAuth”},“request_uri”:“https://crm.yourdomain.com/auth",“method”:"GET”}
request.INFO: Matched route “api_graphql_entrypoint”. {“route”:“api_graphql_entrypoint”,“route_parameters”:{“_route”:“api_graphql_entrypoint”,“_controller”:“api_platform.graphql.action.entrypoint”,“_graphql”:true},“request_uri”:“https://crm.yourdomain.com/api/graphql",“method”:"POST”}

Not sure why it says unable to extract public key…

I got it working, what a mission.
I changed to not point to cert but add it in the .env.local file:
SAML_IDP_X509CERT=‘MIC…’

I also changed the following:
SAML_USERNAME_ATTRIBUTE=‘http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress’
SAML_USE_ATTRIBUTE_FRIENDLY_NAME=false

I am going to continue to test to see if possible to point to a certificate file rather than add the cert in the .env.local. Also for the cert there should be no line breaks that you would see when opening the cert in notepad.

Glad, you found the solution. You can report it on the GitHub too if it is not mentioned already.