Инициировать SingleSignOn с помощью Saml2PostBinding

У меня проблема при использовании ITfoxtec для ASP.NET Core 3.0.
В качестве контекста я пытаюсь установить соединение между веб-приложением и сторонней службой входа в систему. Чтобы заранее инкапсулировать некоторые возможности, сторонняя сторона имеет доступ к нашему URL-адресу метаданных и настроила свои службы для нашего веб-приложения.

Рабочий процесс пользователя:

  • Пользователь входит в веб-приложение;
  • Пользователь нажимает кнопку, которая перенаправляет пользователя в службу входа в систему;
  • Пользователь входит в службу и перенаправляет обратно на указанный returnURL;
  • После этого веб-приложение определяет разрешение на основе предоставленного файла cookie sso.

Предпринятые шаги:

  • Добавлен раздел Saml2 в appsettings.json, содержащий наш metadata.xml и эмитент. Имя издателя совпадает с заданным EntityID, указанным в файле metadata.xml. Он делается анонимным в данном контексте, например:
"Saml2": {
    "IdPMetadata": "wwwroot/SAML/Metadata.xml",
    "Issuer": "myIssuerName",
    "SignatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
    "CertificateValidationMode": "ChainTrust",
    "RevocationMode": "NoCheck",
    "SigningCertificateFile": "\\licenses\\certificate.pfx",
    "SigningCertificatePassword": "password1"
}, 
  • Добавлен Saml2Configuration в startup.cs;
    services
        .Configure<Saml2Configuration>(Configuration.GetSection("Saml2"))
        .Configure<Saml2Configuration>(configuration =>
        {
            configuration.SigningCertificate = CertificateUtil.Load(
                 $"{Environment.WebRootPath}{Configuration["Saml2:SigningCertificateFile"]}",
                 Configuration["Saml2:SigningCertificatePassword"]);
            configuration.AllowedAudienceUris.Add(configuration.Issuer);

            var entityDescriptor = new EntityDescriptor();
                entityDescriptor.ReadIdPSsoDescriptorFromFile(Configuration["Saml2:IdpMetadata"]);

            if (entityDescriptor.IdPSsoDescriptor == null) throw new Exception("Failed to read the metadata.");

            configuration.SignAuthnRequest = true;
            configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices
               .Where(ed => ed.Binding.ToString() == "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
               .First().Location;
            configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
        }); 
  • А вот и сложная часть; По умолчанию инициация sso выполняет запрос с RedirectBinding, который, следовательно, отправляет запрос GET в службу sso. Однако служба, к которой я пытаюсь обратиться, ожидает SAMLRequest в виде запроса POST. Итак, я изменил код, запустив запрос PostBinding, а затем напрямую отправив форму, например:
    public IActionResult Initiate([FromQuery(Name = "returnUrl")] string returnUrl = "")
    {
        var binding = new Saml2PostBinding();
            binding.SetRelayStateQuery(new Dictionary<string, string> { { "ReturnUrl", returnUrl } });
            binding.Bind(new Saml2AuthnRequest(_saml2configuration)
            {
                ForceAuthn = false,
                IsPassive = false,
                NameIdPolicy = new NameIdPolicy() { AllowCreate = true },
                AssertionConsumerServiceUrl = new Uri("https://localhost:44366/api/Authentication/Process"),
            });

        return binding.ToActionResult();
    } 

Проблема:
Однако после отправки AuthnRequest в кодировке base64 в качестве запроса SAML я получаю 403 Forbidden от стороннего входа в систему. На данном этапе я не уверен, правильно ли настроен провайдер идентификации или в моем запросе чего-то не хватает. Что я делаю не так?

Ниже приведены (анонимно сделанные) заголовки запросов.
Предположим, что запрос SAMLRequest предоставляется в виде данных в кодировке base64.

    :authority: myEntityDescriptorName
    :method: POST
    :path: mySsoURL
    :scheme: https
    accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    accept-encoding: gzip, deflate, br
    accept-language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7
    cache-control: no-cache
    content-length: 3582
    content-type: application/x-www-form-urlencoded
    cookie: JSESSIONID=3D5FE88D55674C2F1E3646E6D8A0FFBE
    origin: https://localhost:44366
    pragma: no-cache
    referer: https://localhost:44366/
    sec-fetch-mode: navigate
    sec-fetch-site: cross-site
    sec-fetch-user: ?1
    upgrade-insecure-requests: 1
    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36

person Lucas van Liere    schedule 20.11.2019    source источник


Ответы (1)


Правильно изменить запрос Authn на привязку Post, если это необходимо.

Ваше приложение является поставщиком услуг (также называемым проверяющей стороной), который необходимо настроить у поставщика удостоверений с уникальным именем эмитента.

Я думаю, проблема в том, что имя эмитента, которое вы настроили ("Issuer": "myIssuerName"), неверно. Имя издателя должно быть названием вашего поставщика услуг, а не именем издателя поставщика удостоверений из файла metadata.xml.

person Anders Revsgaard    schedule 21.11.2019
comment
Использование Post Binding действительно работает, однако всякий раз, когда я инициирую свой звонок, я, кажется, получаю форму, тогда как кнопка скрыта тегами ‹noscript›. Есть ли способ мгновенно отправить форму, не удаляя эти теги программно? Или я вынужден заранее инициировать привязку POST? Кроме того, метаданные от поставщика услуг были неверно истолкованы с моей стороны. Я внедрил ITfoxtec Metadata Controller для экспорта моих собственных метаданных, которые впоследствии я предоставил своему поставщику удостоверений для подписи и проверки. - person Lucas van Liere; 21.11.2019
comment
Форма привязки сообщения автоматически отправляется JavaScript, если JavaScript не отключен. Поэтому я думаю, что в клиентском браузере отключен JavaScript. Вы можете попробовать протестировать с помощью другого браузера или, может быть, вы используете браузер на сервере. - person Anders Revsgaard; 22.11.2019
comment
Я сомневаюсь, что это связано с клиентским браузером. Если проверить параметры браузера Chrome или Mozilla, я вижу, что они включены в параметрах обоих браузеров. Может ли быть, что .NET Core использует SpaStaticFiles для размещения файлов Angular и поэтому рассматривается как браузер, работающий на сервере? В любом случае, как ITfoxtec.Identity.SAML проверяет, включен ли JavaScript, чтобы я мог предотвратить это? - person Lucas van Liere; 22.11.2019
comment
Я не слышал о других проблемах с автоматической отправкой, боюсь, что у меня нет хорошего ответа. Если JavaScript отключен, должна появиться кнопка ‹input type = submit value = Continue /›, в противном случае она будет скрыта тегом ‹noscript›. Если вы найдете лучший способ автоматической отправки, сообщите об этом. Но насколько мне известно, это должно сработать. - person Anders Revsgaard; 22.11.2019
comment
В качестве обходного пути я преждевременно добавил форму во внешний интерфейс и запросил Saml2PostBinding при загрузке страницы. После завершения запроса я помещаю значения SAMLRequest в свою форму, которые я отправляю всякий раз, когда пользователь нажимает кнопку входа в систему. Он работает, к счастью, не кажется хакерским и предоставляет мне свежую подпись для каждой попытки. Однако это как бы разрушает цель автоматической отправки. - person Lucas van Liere; 22.11.2019
comment
Это безопасный обходной путь. Однако я удивлен, что автоматическая отправка не работает. Когда IdP вернет ответ SAML 2.0 Authn вашему приложению, это, вероятно, также будет отправлено с помощью формы. Можно ли увидеть, что отличается от того, как выполняется автоматическая отправка в ITfoxtec Identity SAML 2.0? - person Anders Revsgaard; 25.11.2019
comment
Единственное отличие, которое я смог найти, - это заголовок Accept, тогда как IdP поддерживает text / html, а мой - нет. Раньше я пытался манипулировать этим конкретным заголовком, но по какой-то причине он игнорировался при любом вызове, который я пытался сделать с помощью ITfoxtec Identity. Возможно, автоматическая отправка не может определить, включен ли JavaScript, если тип ответа не разрешен заголовками принятия запроса? - person Lucas van Liere; 25.11.2019
comment
Спасибо за расследование. Боюсь, я до сих пор не знаю, почему это не удается. ContentType = text / html фактически указывается в пакете. Я рад, что вы нашли обходной путь. - person Anders Revsgaard; 26.11.2019