Хобрук: Ваш путь к мастерству в программировании

Как получить ответ SAML от OKTA для модульного / интеграционного тестирования

Я работаю над проектом, где они проходят аутентификацию через SAML от OKTA. У меня успешно работает интеграция, когда на веб-сайт отправляется ответ SAMLResponse (с помощью метода POST).

В истинном стиле TDD я начал с написания нескольких модульных тестов. Мои модульные тесты принимают ответ SAMLResponse (который закодирован в Base64). Однако все мои модульные тесты работают, поскольку SAMLResponse имеет время жизни (истекает) всего несколько минут, мои модульные тесты прерываются через несколько минут.

Поэтому мне нужно периодически входить в OKTA, а затем с помощью инструментов разработчика Chrome фиксировать трафик, отправляемый на мой сайт разработки. Затем я копирую и вставляю SAMLResponse в свои модульные тесты и возвращаюсь к прохождению модульных тестов. Очевидно, это нежелательная ситуация.

Итак, мой вопрос: как я могу автоматически войти в Okta (желательно на C #), чтобы получить ответ SAML? Я предполагаю, что есть какой-то URL-адрес, на который я могу отправить POST с именем пользователя и паролем и получить ответ SAMLReponse. Все мои попытки Скрипача понять требуемое общение разочаровали меня. Я ищу любые рекомендации, которые у вас могут быть. Заранее спасибо.


  • Я не знаком с SAML, но, судя по вашему вопросу, я думаю, что вы либо тестируете на неправильном уровне, либо нуждаетесь в дальнейшей абстракции. Я бы заметил, что то, где вы обрабатываете ответ, не должно иметь значения для фактического сообщения, а больше от содержания сообщения, то есть возможность подделать ответ должна работать. Я бы никогда не ожидал, что модульный тест когда-либо вызовет внешнюю функцию и вызовет тревогу, если ему нужно будет войти во внешнее приложение. 13.01.2017
  • Согласованный. Сейчас это действительно становится интеграционным тестом. Если срок действия SAMLResponses не истекает, это действительно может быть модульный тест, но, согласно Okta, это не вариант. Учитывая сложность интеграции SAML, мы полагаемся на наши тесты для еженедельного поиска проблем с конфигурацией. 13.01.2017
  • По поводу вашего комментария о возможности подделать ответ. Это было то, что я изначально пробовал, однако ответы (которые представляют собой просто строки Base 64) содержат информацию, подписанную сертификатом. Поэтому, если вы что-то измените в ответе, проверка не удастся. Я знаю, что нарушаю некоторые передовые методы модульного тестирования, но SAML и OKTA загнали меня в угол, но я все еще не собираюсь отказываться от своих интеграционных тестов, поскольку я извлекаю из них большую ценность ... просто хочу, чтобы они были автоматизировано. 13.01.2017

Ответы:


1

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

Спасибо Joël Franusic за указатели. Я реализовал его решение 1.2 (пользовательский агент с клиентом Okta). Между его ссылками и несколькими другими частями документации на веб-сайте Okta я смог в конечном итоге собрать рабочий код.

private static async Task<string> GetTestSamlResponse()
    {
        try
        {
            // settings specific to my Okta instance
            string username = "USERNAME GOES HERE";
            string password = "PASSWORD GOES HERE";
            var apiToken = "API TOKEN GOES HERE";

            // this is the unique domain issued to your account.  
            // If you setup a dev account you'll have a domain in the form https://dev-<AccountNumber>.oktapreview.com.
            // account number is a unique number issues by Okta when you sign up for the account
            var baseUrl = "YOUR BASE URL GOES HERE";

            // In Okta Admin UI, click "Applications" in main menu, choose your app, click "Sign On" tab.  Under Sign On Methods, then under SAML 2.0, click "View Setup Instructions"
            // Get the url called "Identity Provider Single Sign-On URL", paste it in th below line
            var ssoUrl = "YOUR SSO URL GOES HERE";

            // construct an Okta settings object
            var settings = new Okta.Core.OktaSettings
            {
                ApiToken = apiToken,
                BaseUri = new Uri(baseUrl)
            };

            // get session token from Okta
            var authClient = new Okta.Core.Clients.AuthClient(settings);
            var authResponse = authClient.Authenticate(username, password);
            var sessionToken = authResponse.SessionToken;

            // start session and get a cookie token
            var sessionsClient = new Okta.Core.Clients.SessionsClient(settings);
            var session = sessionsClient.CreateSession(sessionToken);
            var cookieToken = session.CookieToken;

            // using the cookie token, get the SAMLResponse from Okta via a HTTP GET.
            var httpClient = new System.Net.Http.HttpClient();

            // add User-Agent header, because apparently Okta is expecting this information.  
            // If you don't pass something, the Okta site will return a 500 - Internal Server error
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "UnitTest");

            // add the cookie token to the URL query string
            string url = string.Format("{0}?onetimetoken={1}", ssoUrl, cookieToken);

            // do the HTTP GET
            using (var response = await httpClient.GetAsync(url))
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    // read the HTML returned
                    string html = await response.Content.ReadAsStringAsync();

                    // parse the HTML to get the SAMLResponse (using HtmlAgilityPack from NuGet)
                    HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
                    htmlDoc.LoadHtml(html);
                    // from the input field called SAMLResponse, get the "value" attribute
                    string samlResponse = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='SAMLResponse']").Attributes["value"].Value;
                    return samlResponse;
                }
                else
                    throw new Exception(string.Format("Error getting SAML Response {0}", response.StatusCode));
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }
16.01.2017

2

Есть несколько способов провести тестирование, которое вы предлагаете, и вот что сразу приходит на ум:

  1. Напишите простой HTTP-агент пользователя на C #, используя такую ​​библиотеку, как RestSharp или аналогичную.
  2. Создайте интеграционный тест с использованием внешнего ложного IdP.
  3. Измените SAMLResponse и повторно подпишите его собственным ключом.

Я подробно расскажу о каждом подходе ниже.

Написание простого HTTP-агента пользователя

Я предлагаю этот метод, предлагаю воспользоваться одним из следующих двух подходов:

  1. Напишите общий пользовательский агент, который будет определять и заполнять поля формы имени пользователя и пароля. Я написал инструмент на Python под названием «saml-messenger», который использует этот подход, основной код находится в файле с именем messenger.py.
  2. Используйте API Okta для получения токена сеанса и используйте его для получения SAMLResponse. Этот подход. Код для получение токена сеанса и обмен токена сеанса на SAMLResponse находятся в src/main/java/com/okta/tools/awscli.java файле.

Первый подход является более общим и должен работать с любым IdP с полем имени пользователя и пароля. Второй подход, вероятно, то, что вы ищете, но он специфичен для Okta.

В любом случае я предлагаю создать в Okta специального пользователя, который заблокирован и используется только для тестирования.

Создание интеграционного теста для фиктивного IdP

При таком подходе вам потребуется создать фиктивный IdP, который будет выдавать вам SAMLResponse без аутентификации. Я использовал saml-idp, чтобы сделать это раньше.

Достоинством этого подхода является то, что он должен требовать меньше C # для написания, за счет принятия другой зависимости.

Изменение повторной подписи SAMLResponse

На самом деле я включаю сюда этот вариант только для полноты картины и как способ предостеречь вас от использования этого подхода. Узнав о SAML, вы столкнетесь лицом к лицу с безумием и сожалением. Я не предлагаю такой подход.

13.01.2017
Новые материалы

Прогресс в технологии Трансформеров часть 3
Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

Приключения в Javascript, часть 1
Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

Понимание дженериков в TypeScript: подробное руководство
Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

Учебные заметки JavaScript Object Oriented Labs
Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

Разбор строк запроса в vue.js
Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
«Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..