Как мы добавили поддержку единого входа в 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 обеспечивает упреждающий подход. Мы не только знали, что у некоторых наших клиентов возникли проблемы с новой функцией, но и видели причину ошибки, прежде чем они даже связались с нами, чтобы сообщить, что ошибка произошла в первую очередь.
С 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 является лишь небольшим шагом в постоянно растущей экосистеме элементов, которые компании хотят, нуждаются или должны интегрировать. Мы можем потратить время, пытаясь предвидеть различные крайние случаи, но это не практично, и в большинстве случаев вы не можете предвидеть будущее. Вот почему вам нужны инструменты, которые помогут вам справляться с ростом ваших продуктов, выявляя и идентифицируя первопричину возникновения ошибок — до того, как ваши клиенты пожалуются на это.