SpBundle icon indicating copy to clipboard operation
SpBundle copied to clipboard

Invalid inbound message destination

Open guiyomh opened this issue 8 years ago • 16 comments

when i'm redirect to /saml/login_check

i have a error :

Invalid inbound message destination "http://xxxxx/saml/login_check"

guiyomh avatar Sep 12 '17 08:09 guiyomh

Hi @guiyomh

I have the same issue here. My app is behind a proxy. The proxy handles the certificate, so the route for login_check is not the right one.

In short, the login_check route from the outside is https://publicdomain.com/saml/login_check. And once it passes the proxy, it becomes http://insidedomain.local/saml/login_check.

I think the way should be to tell SpBundle to trust http://insidedomain.local/saml/login_check.

Is your issue the same as mine? Did you find a solution?

ChMat avatar Oct 05 '17 10:10 ChMat

It means that in your own EntityDescriptor there are no AssertionConsumerService endpoints with such Location. If you're behind a proxy, your metadata must state the public url, and IDP must return Response with public url destination, so AbstractDestinationValidatorAction will be able to find that url from the Reponse in your own EntityDescriptor.

Provide your own metadata xml, sent AuthnRequest, and received Response, and we can compare the values and see what is wrong.

tmilos avatar Oct 06 '17 06:10 tmilos

Thanks @tmilos for the information. It helped me solve the issue.

I implemented a custom service extending LightSaml\Builder\EntityDescriptor\SimpleEntityDescriptorBuilder.

I replaced the $acsUrl __construct() parameter to an array.

So when I declare the service, the corresponding argument will be an array containing the login_check url from behind the proxy (http and .local url in my case) and from the rest of the world, like this:

["http://mysite.local/saml/login_check", "https://mysite.com/saml/login_check"]

And I changed the getSpSsoDescriptor() function as follows:

    /**
     * @return SpSsoDescriptor|null
     */
    protected function getSpSsoDescriptor()
    {
        if (null === $this->acsUrl) {
            return null;
        }

        $spSso = new SpSsoDescriptor();

        foreach ($this->acsBindings as $index => $biding) {
            if (is_array($this->acsUrl)) {
                foreach ($this->acsUrl as $acsUrl) {
                    $acs = new AssertionConsumerService();
                    $acs->setIndex($index)->setLocation($acsUrl)->setBinding($biding);
                    $spSso->addAssertionConsumerService($acs);
                }
            }
            else
            {
                $acs = new AssertionConsumerService();
                $acs->setIndex($index)->setLocation($this->acsUrl)->setBinding($biding);
                $spSso->addAssertionConsumerService($acs);
            }
        }

        $this->addKeyDescriptors($spSso);

        return $spSso;
    }

This worked for me, I hope this will help.

ChMat avatar Oct 16 '17 11:10 ChMat

Hi @ChMat I'm having the same trouble as you had, I'm wondering to know if you changed that function on SimpleEntityDescriptorBuilder file on the vendor directory? If not, how did you do? Thanks!

jhonnynho avatar Mar 22 '19 04:03 jhonnynho

Hi @jhonnynho

As I wrote, I created a class in my application that extends LightSaml\Builder\EntityDescriptor\SimpleEntityDescriptorBuilder.

This class contains the getSpSsoDescriptor() function that overrides the parent function with my custom behaviour.

It looks like this (you'll probably want to adapt the namespace):

// Service/AppEntityDescriptor.php
<?php

namespace AppBundle\Service;

use LightSaml\Builder\EntityDescriptor\SimpleEntityDescriptorBuilder;
use LightSaml\Model\Metadata\AssertionConsumerService;
use LightSaml\Model\Metadata\KeyDescriptor;
use LightSaml\Model\Metadata\SpSsoDescriptor;
use LightSaml\SamlConstants;
use LightSaml\Credential\X509Certificate;

/**
 * Class AppEntityDescriptor
 *
 * @package AppBundle\Service
 */
class AppEntityDescriptor extends SimpleEntityDescriptorBuilder
{
	/** @var array|string */
	protected $acsUrl;

	/**
	 * @param string          $entityId
	 * @param array|string    $acsUrl
	 * @param string          $ssoUrl
	 * @param string          $ownCertificate
	 * @param string[]        $acsBindings
	 * @param string[]        $ssoBindings
	 * @param string[]|null   $use
	 */
	public function __construct(
		$entityId,
		$acsUrl,
		$ssoUrl,
		$ownCertificate,
		array $acsBindings = array(SamlConstants::BINDING_SAML2_HTTP_POST),
		array $ssoBindings = array(SamlConstants::BINDING_SAML2_HTTP_POST, SamlConstants::BINDING_SAML2_HTTP_REDIRECT),
		$use = array(KeyDescriptor::USE_ENCRYPTION, KeyDescriptor::USE_SIGNING)
	) {
		$certificate = $ownCertificate;

		if (!$ownCertificate instanceof X509Certificate) {
			$certificate = new X509Certificate();
			$certificate->loadFromFile($ownCertificate);
		}

		parent::__construct($entityId, $acsUrl, $ssoUrl, $certificate, $acsBindings, $use);
	}

	/**
	 * @return SpSsoDescriptor|null
	 */
	protected function getSpSsoDescriptor()
	{
		if (null === $this->acsUrl) {
			return null;
		}

		$spSso = new SpSsoDescriptor();

		foreach ($this->acsBindings as $index => $binding) {
			// On ajoute toutes les url autorisées pour le service
			if (is_array($this->acsUrl)) {
				foreach ($this->acsUrl as $acsUrl) {
					$acs = new AssertionConsumerService();
					$acs->setIndex($index)->setLocation($acsUrl)->setBinding($binding);
					$spSso->addAssertionConsumerService($acs);
				}
			}
			else
			{
				$acs = new AssertionConsumerService();
				$acs->setIndex($index)->setLocation($this->acsUrl)->setBinding($binding);
				$spSso->addAssertionConsumerService($acs);
			}
		}

		$this->addKeyDescriptors($spSso);

		return $spSso;
	}

}

And in my services.yml:

    app_entity_descriptor:
        class: AppBundle\Service\AppEntityDescriptor
        arguments:
            - "%entity_id%"
            - ["http://local.domain/saml/login_check", "https://public.domain/saml/login_check"]
            - "https://sso.server/saml2/idp/SSOService.php"
            - "%kernel.root_dir%/config/cert/saml.crt"

Finally, I add the service to LightSaml configuration in app/config/config.yml

light_saml_symfony_bridge:
    own:
        entity_id: "https://your.entity.id" # required
        entity_descriptor_provider:
            id: app_entity_descriptor

I hope this helps.

ChMat avatar Mar 22 '19 10:03 ChMat

Thank you @ChMat , I'm going to test it, but I have a doubt, did you edit something else? I mean on the security.yaml or in the ligh_saml_symfony_bridge.yaml. I think this it won't run automatically.

I don't now if you add something lie this on the security.yaml

check_path: app_entity_descriptor

jhonnynho avatar Mar 24 '19 04:03 jhonnynho

light_saml_symfony_bridge:
    own:
        entity_id: https://your.entity.id # required
        entity_descriptor_provider:
            id: app_entity_descriptor

As here https://www.lightsaml.com/Symfony-Bridge/Configuration/

tmilos avatar Mar 24 '19 06:03 tmilos

Thanks for pointing that @jhonnynho ! Like @tmilos wrote right above, you have to configure it in your config.yml.

I have updated my comment above so the reply is complete and correct.

ChMat avatar Mar 25 '19 10:03 ChMat

Ey @ChMat and @tmilos I did this steps but now I'm having this Unknown InResponseTo '_77ce4c02e5bedb405c4ca19289f80a8a2967db504f' My SSO system is on SimpleSAMLPHP. I don't know what can I do. I have Symfony 4, and this is my configuration:

light_saml_symfony_bridge:
    own:
        entity_id: https://gateway.com/saml/
        entity_descriptor_provider:
            id: app_entity_descriptor
        credentials:
            -
                certificate: "%kernel.root_dir%/../vendor/lightsaml/lightsaml/web/sp/saml.crt"
                key:         "%kernel.root_dir%/../vendor/lightsaml/lightsaml/web/sp/saml.key"
                password:    ~
    party:
        idp:
            files:
                - "%kernel.root_dir%/../src/Idp/idp.xml"
#                - "%kernel.root_dir%/../vendor/lightsaml/lightsaml/web/sp/openidp.feide.no.xml"
    store:
        id_state: id_store

security.yaml

        main:
            anonymous: ~
            light_saml_sp:
                provider: db_provider       # user provider name configured in step 9
                user_creator: user_creator  # name of the user creator service created in step 10
                login_path: /saml/login
                check_path: /saml/login_check
                default_target_path: /
                require_previous_session: true
            logout:
                path: /logout

services.yaml

    app_entity_descriptor:
        class: App\Services\AppEntityDescriptor
        arguments:
            - "%entity_id%"
            - ["%secure_login_check%", "%unsecure_login_check%"]
            - "%saml_sso_service%"
            - "%kernel.root_dir%/../vendor/lightsaml/lightsaml/web/sp/saml.crt"

jhonnynho avatar Mar 25 '19 20:03 jhonnynho

Hi @jhonnynho

Usually, you get this kind of response either:

  • when you try to replay a previous authentication process
  • or when the service provider is not the one that emitted the authentication request

Note that the entity_id must match exactly the one that is registered in your SimpleSAMLphp idp.

It may be the entity_id because the light_saml_symfony_bridge.own.entity_id is defined by a string locally while the entity_id in your services.yaml comes from a parameter that we do not see in your comment.

ChMat avatar Mar 25 '19 22:03 ChMat

Hi @ChMat

Services.yaml

entity_id: '%env(ENTITY_ID)%'
saml_sso_service: '%env(SAML_SSO_SERVICE)%'
secure_login_check: '%env(SECURE_LOGIN_CHECK)%'
unsecure_login_check: '%env(UNSECURE_LOGIN_CHECK)

.env

ENTITY_ID=https://gateway.com/saml/
UNSECURE_LOGIN_CHECK=http://gateway/saml/login_check
SECURE_LOGIN_CHECK=https://gateway/saml/login_check
SAML_SSO_SERVICE=https://account.com/simplesaml/saml2/idp/SSOService.php

There are my params, and that error happens after doing the login on SimpleSamlPHP On SimplesamlPHP I have the same entity_id

jhonnynho avatar Mar 25 '19 22:03 jhonnynho

Check your light_saml_symfony_bridge config. You have an entity_id that is different from that of your .env: https://sso-gateway/saml/

Both should be identical.

ChMat avatar Mar 25 '19 22:03 ChMat

I have exactly the same entity_id on my config and on SimpleSaml

jhonnynho avatar Mar 25 '19 22:03 jhonnynho

Hi guys, I've got the same problem, The Saml is behind an haproxy, and I recieve error Unknown InResponseTo ... , when I try to login, I don't know if the saml needs something else, because the ssl end-to-end isn't available with haproxy in front of my saml service.

JavierBmrg avatar Mar 26 '19 01:03 JavierBmrg

Thanks @tmilos for the information. It helped me solve the issue.

I implemented a custom service extending LightSaml\Builder\EntityDescriptor\SimpleEntityDescriptorBuilder.

I replaced the $acsUrl __construct() parameter to an array.

So when I declare the service, the corresponding argument will be an array containing the login_check url from behind the proxy (http and .local url in my case) and from the rest of the world, like this:

["http://mysite.local/saml/login_check", "https://mysite.com/saml/login_check"]

And I changed the getSpSsoDescriptor() function as follows:

    /**
     * @return SpSsoDescriptor|null
     */
    protected function getSpSsoDescriptor()
    {
        if (null === $this->acsUrl) {
            return null;
        }

        $spSso = new SpSsoDescriptor();

        foreach ($this->acsBindings as $index => $biding) {
            if (is_array($this->acsUrl)) {
                foreach ($this->acsUrl as $acsUrl) {
                    $acs = new AssertionConsumerService();
                    $acs->setIndex($index)->setLocation($acsUrl)->setBinding($biding);
                    $spSso->addAssertionConsumerService($acs);
                }
            }
            else
            {
                $acs = new AssertionConsumerService();
                $acs->setIndex($index)->setLocation($this->acsUrl)->setBinding($biding);
                $spSso->addAssertionConsumerService($acs);
            }
        }

        $this->addKeyDescriptors($spSso);

        return $spSso;
    }

This worked for me, I hope this will help.

Thanks @ChMat It works like a charm!

jonhleno avatar Oct 01 '19 12:10 jonhleno

hi guys, theres a way to do similar escenario but for de endpoint "default_target_path", actually is calling my unsecured endpoint but i need that be redirected to the secured endpoint. I already did the same for the login_check and is working succesfully but i need also for the default_target_path wheres my codebehind do some validations for login user.

image

bastianpsycho1 avatar Aug 16 '23 23:08 bastianpsycho1