Статьи

Как реализовать корпоративное управление пользователями с поддержкой единого входа Java SAML (и оставаться в живых)

Как мы добавили поддержку единого входа в SAML и отладили его в производстве

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

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

Давайте погрузимся в.

Что такое SAML и для чего он хорош?

SAML, S ecurity A ssertion M arkup L anguage, является открытым стандартным форматом данных для обмена данными аутентификации и авторизации между компаниями и поставщиками услуг. Это протокол безопасности, похожий на OpenId, OAuth (о котором мы также писали здесь ), Kerberos и другие.

Одним из основных вариантов использования адресов SAML является единый вход в систему (SSO) для всех сервисов, чтобы обеспечить простой вход в систему через другие сервисы. Например, опыт использования учетной записи Google для регистрации в Stackoverflow. Применяя единый вход, компании могут использовать протокол для контроля доступа.

Этот метод обеспечивает большую ценность как для пользователя, так и для компании. Пользователям не нужно иметь дело с паролями для различных приложений и запоминать их, но при этом предоставлять им необходимую информацию и услуги. Компании могут легко идентифицировать внутренних пользователей, предоставляя им необходимые данные. Кроме того, в случае, если сотрудник уходит из компании, проще отозвать одну основную учетную запись без необходимости проходить поиск и искать несколько учетных записей для каждой службы, к которой у этого пользователя был доступ.

Реализация SAML

SAML используется для определения 2 сторон в процессе аутентификации:

  • Поставщик услуг — сервис, в который пользователь хочет войти
  • Поставщик удостоверений — пользователь, который хочет получить доступ к услуге

Эти 2 провайдера устанавливают доверие, передавая файлы метаданных XML от одного к другому. Это однократный шаг настройки. Впоследствии, когда пользователь пытается получить доступ к службе, SAMLRequest и SAMLResponse являются строками XML, которые отправляются между двумя поставщиками и выполняют фактическую аутентификацию. Это однократный процесс, который позволяет пользователям выполнять единый вход для желаемого приложения.

Это не САМ (L) E для всех

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

Это одна из проблем, с которой мы столкнулись здесь в OverOps при реализации поддержки SAML для инструмента, который мы создаем. У нас есть разные клиенты, начиная от небольших стартапов с 5 сотрудниками и заканчивая корпоративными компаниями с тысячами пользователей. Хотя мы поддерживаем вход в систему с использованием пароля, а также OAuth с использованием Google или Github, мы хотели, чтобы компании с существующими решениями SAML могли беспрепятственно входить в наш сервис. И поэтому нам нужно было поддерживать несколько провайдеров идентификации, таких как: Okta, PingOne, SSOCircle, OneLogin и других.

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

Как мы это сделали? Тестирование в производстве

Когда мы впервые внедрили новую функцию SAML, мы развернули ее в бета-версии и попытались протестировать как можно больше поставщиков. Мы знали, что в ходе этого процесса мы можем столкнуться с некоторыми различиями, и хотели посмотреть, какие проблемы могут возникнуть.

Для большинства компаний этот процесс работал без нареканий, но мы столкнулись с некоторыми проблемами. Некоторые компании использовали другую кодировку для своих строк, другие компании не передавали стандартные атрибуты (имя, фамилию и т. Д.) Со стандартными именами атрибутов, а некоторые компании имели собственные реализации.

Так как мы используем OverOps для нашей собственной производственной среды, мы смогли легко увидеть SAMLResponse, который не работал у некоторых клиентов и что привело к его отказу. Из-за этого воспроизвести ошибку в нашей среде разработки было довольно просто, и мы создали модульные тесты с заданным вводом.

Это то, что мы имеем в виду, когда говорим, что OverOps обеспечивает упреждающий подход. Мы не только знали, что у некоторых наших клиентов возникли проблемы с новой функцией, но и видели причину ошибки, прежде чем они даже связались с нами, чтобы сообщить, что ошибка произошла в первую очередь.

На этом изображении мы видим SAMLResponse, который мы смогли проанализировать, и видим, что тренд спал, используя график.

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

Внедрение SAML в OverOps

Для начала мы использовали Dead Simple SAML 2.0 Client в качестве эталона, поскольку первым поставщиком, которого мы хотели поддержать, была Okta. Автор этого репо, Мартин Лапорт , реализовал специальный случай для его обработки, а также дал простое и простое использование SAML, которое сработало. И быстро мы создали индивидуальную версию, чтобы соответствовать нашим собственным потребностям.

Кроме того, поскольку решения SAML обычно не нуждаются в поддержке нескольких типов поставщиков, обычно метаданные IdP помещаются в файл XML и просто загружаются. Но поскольку в нашем случае мы хотели поддерживать возможность настройки новых метаданных IdP онлайн для каждой компании, а также загружать правильные метаданные для нужной компании, мы сохранили их во внутренней базе данных, где ключом является название компании, и метаданными. это значение.

Итак, наш код выглядит примерно так:

1
String companyMetadata = DB.getCollection(“SAMLMetadata”).getByKey(companyName);

Затем мы можем использовать StringReader для передачи считывателя в SamlClient.fromMetadata:

1
SamlClient samlClient = SamlClient.fromMetadata("", assertionConsumer, new StringReader(idpMetadata));

И, наконец, мы вызываем decodeAndValidateSamlResponse с закодированным SAMLResponse, о котором мы говорили ранее:

1
samlClient.decodeAndValidateSamlResponse(encodedSAMLResponse)

DecodeAndValidateSamlResponse выполняет этот код, который в основном проверяет, соответствует ли ответ стандартному формату SAMLResponse, и выполняет на нем декодирование base64, анализирует и проверяет.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public SamlResponse decodeAndValidateSamlResponse(String encodedResponse) throws SamlException
    {
        String decodedResponse;
         
        try
        {
            decodedResponse = new String(Base64.decode(encodedResponse), "UTF-8");
        }
        catch (UnsupportedEncodingException ex)
        {
            throw new SamlException("Cannot decode base64 encoded response", ex);
        }
         
        logger.trace("Validating SAML response: " + decodedResponse);
         
        Response response;
         
        try
        {
            DOMParser parser = new DOMParser();
            parser.parse(new InputSource(new StringReader(decodedResponse)));
             
            response =
                    (Response)Configuration.getUnmarshallerFactory()
                    .getUnmarshaller(parser.getDocument().getDocumentElement())
                    .unmarshall(parser.getDocument().getDocumentElement());
        }
        catch (IOException ex)
        {
            throw new SamlException("Cannot decode xml encoded response", ex);
        }
        catch (SAXException ex)
        {
            throw new SamlException("Cannot decode xml encoded response", ex);
        }
        catch (UnmarshallingException ex)
        {
            throw new SamlException("Cannot decode xml encoded response", ex);
        }
         
        validateResponse(response);
        validateAssertion(response);
        validateSignature(response);
         
        Assertion assertion = response.getAssertions().get(0);
        return new SamlResponse(assertion);
    }

Не все идеально

Эти интеграции включают в себя МНОГО технических деталей, и запись каждого сеанса добавит огромное количество шума в ваши журналы. В некоторых случаях вы даже не можете знать, что вам следует регистрировать, поскольку ошибки являются совершенно неожиданными и могут появиться только в производстве. Вот почему OverOps был необходим для своевременного устранения ошибки, с которой мы столкнулись. Чтобы увидеть, как это работает, посмотрите это живое демо .

Кроме того, хотя наш случай относится к SAML, он отражает проблемы, с которыми сталкиваются компании при разработке больших систем, имеющих много различных движущихся частей. Мы, как компания, хотим поддерживать как можно больше инструментов, плагинов, интеграций и других возможностей, и хотя клиент всегда прав, их вклад может быть неправильным. Или, по крайней мере, неожиданно.

Последние мысли

Внедрение SAML является лишь небольшим шагом в постоянно растущей экосистеме элементов, которые компании хотят, нуждаются или должны интегрировать. Мы можем потратить время, пытаясь предвидеть различные крайние случаи, но это не практично, и в большинстве случаев вы не можете предвидеть будущее. Вот почему вам нужны инструменты, которые помогут вам справляться с ростом ваших продуктов, выявляя и идентифицируя первопричину возникновения ошибок — до того, как ваши клиенты пожалуются на это.