Перейти к основному содержимому

Защита веб-служб SOAP с помощью Keycloak

· 8 мин. чтения

1. Обзор

Keycloak — это сервер управления идентификацией и доступом с открытым исходным кодом, который защищает наши современные приложения (такие как SPA, мобильные приложения, API и т. д.). Keycloak поддерживает стандартные отраслевые протоколы, такие как язык разметки подтверждения безопасности (SAML) 2.0, единый вход (SSO) и OpenID Connect Connect (OIDC) .

Кроме того, в этом руководстве мы узнаем, как использовать Keycloak для аутентификации и авторизации веб-служб SOAP с использованием OIDC (OpenID Connect).

2. Разработайте веб-службу SOAP

Вкратце, давайте узнаем, как создать веб-службу SOAP с помощью Spring Boot.

2.1. Операции веб-службы

Сразу определимся с операциями:

  • getProductDetails : возвращает информацию о продукте для данного идентификатора продукта. Также предположим, что пользователь с ролью пользователя может запросить эту операцию.
  • deleteProduct : удаляет продукт для данного идентификатора продукта. Кроме того, только пользователь с правами администратора может запросить эту операцию.

Мы определили две операции и RBAC (управление доступом на основе ролей) .

2.2. Определить XSD

Прежде всего, давайте определим product.xsd :

<xs:element name="getProductDetailsRequest">
...
</xs:element>
<xs:element name="deleteProductRequest">
...
</xs:element>
...
</xs:schema>

Также давайте добавим зависимости wsdl4j и Spring Boot Webservices :

<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
<version>2.5.4</version>
</dependency>

2.3. Веб-сервис

Далее давайте разработаем веб-сервис SOAP.

@PayloadRoot(namespace = "http://www.foreach.com/springbootsoap/keycloak", localPart = "getProductDetailsRequest")
@ResponsePayload
public GetProductDetailsResponse getProductDetails(@RequestPayload GetProductDetailsRequest request) {
...
}
@PayloadRoot(namespace = "http://www.foreach.com/springbootsoap/keycloak", localPart = "deleteProductRequest")
@ResponsePayload
public DeleteProductResponse deleteProduct(@RequestPayload DeleteProductRequest request) {
...
}

Мы можем протестировать эту веб-службу с помощью нескольких инструментов, таких как cURL , Postman , SOAPUI и т. д. Теперь давайте посмотрим, как защитить нашу веб-службу SOAP.

3. Настройка Keycloak

Для начала давайте настроим Keycloak для защиты нашего веб-сервиса с помощью OpenId Connect.

3.1. Создать клиента

Как правило, Клиент — это приложение, для которого требуется служба аутентификации Keycloaks . Также при создании клиента выберите:

  • URL-адрес приложения в качестве корневого URL -адреса
  • openid-connect в качестве клиентского протокола
  • Конфиденциально как тип доступа
  • Включите авторизацию и учетную запись службы.

Кроме того, включение сервисных учетных записей позволяет нашему приложению (клиенту) проходить аутентификацию с помощью Keycloak. Впоследствии он предоставляет поток типа Client Credentials Grant для нашего потока аутентификации:

./8ffb2bddae8d1926c1eb49ee63c960c0.jpeg

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

3.2. Пользователи и роли

Далее создадим двух пользователей и назначим им роли и пароли:

./ddad84043a12c4fd00665b666e8b147f.jpeg

Во-первых, давайте создадим роли администратора и пользователя. Keycloak позволяет нам создавать два типа ролей — роли Realm и клиентские роли . Однако сначала давайте создадим клиентские роли .

Нажмите « Клиенты», выберите клиента и перейдите на вкладку «Роли ». Затем создайте две роли, администратора и пользователя:

./facb6a433ddbc69e3650dcd2d6c59eb1.jpeg

Хотя Keycloak может извлекать пользователей из LDAP или AD (Active Directory), для простоты давайте вручную настроим пользователей и назначим им роли.

Создадим двух пользователей. Сначала мы нажимаем « Пользователи», затем «Добавить пользователя » :

./71fe2297cb253811589ee08e997d9459.jpeg

Теперь давайте распределим роли между пользователями.

Снова нажмите « Пользователи », выберите пользователя и нажмите « Изменить», затем перейдите на вкладку « Сопоставление ролей », выберите клиента из « Роли клиента» и выберите роль в « Доступных ролях». Назначим роль администратора одному пользователю, а роль пользователя — другому:

./f7244b49178ad1a05b2ebd67406a120b.jpeg

4. Конфигурация весенней загрузки

Точно так же давайте защитим наши веб-службы SOAP.

4.1. Keycloak — интеграция с Spring Boot

Во-первых, давайте добавим зависимости Keycloak.

Keycloak предоставляет адаптер, который использует автоматическую настройку Spring Boot и упрощает интеграцию . Теперь давайте обновим наши зависимости, чтобы включить этот адаптер Keycloak :

<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>15.0.2</version>
</dependency>

Далее добавим конфигурацию Keycloak в наш application.properties :

keycloak.enabled=true
keycloak.realm=foreach-soap-services
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.bearer-only=true
keycloak.credentials.secret=14da6f9e-261f-489a-9bf0-1441e4a9ddc4
keycloak.ssl-required=external
keycloak.resource=foreach-soap-services
keycloak.use-resource-role-mappings=true

Из документации Keycloak :

  • keycloak.enabled : разрешить включение адаптера Keycloak Spring Boot по конфигурации. Значение по умолчанию — истина.
  • keycloak.realm : Имя области Keycloak и является обязательным.
  • keycloak.auth-server-url : базовый URL является обязательным и относится к серверу Keycloak. Обычно он имеет вид http(s)://host:port/auth.
  • keycloak.bearer-only : хотя значение по умолчанию равно false, установите для него значение true , чтобы адаптер мог проверить токены.
  • keycloak.credentials. secret : обязательный секрет клиента, настроенный в Keycloak.
  • keycloak.ssl-required : значение по умолчанию — external . Другими словами, все внешние запросы (кроме localhost ) должны быть по протоколу https .
  • keycloak.resource : обязательный идентификатор клиента приложения.
  • keycloak.use-resource-role-mappings : несмотря на то, что по умолчанию установлено значение false , установите для него значение true , чтобы адаптер просматривал токен в поисках сопоставлений ролей на уровне приложения для пользователя.

4.2. Включить глобальную безопасность метода

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

Существует два способа установки ограничений:

  1. Объявите ограничения безопасности и коллекции безопасности в файле конфигурации приложения.
  2. Безопасность на уровне метода с использованием @EnableGlobalMethodSecurity .

Для веб-служб SOAP ограничения безопасности не обеспечивают точного контроля. Более того, объявление этих ограничений слишком многословно.

Впредь давайте использовать возможности @EnableGlobalMethodSecurity для защиты операций веб-службы SOAP.

4.3. Определение KeycloakWebSecurityConfigurerAdapter

KeycloakWebSecurityConfigurerAdapter — необязательный удобный класс, расширяющий WebSecurityConfigurerAdapter и упрощающий настройку контекста безопасности . Далее давайте определим класс KeycloakSecurityConfig , который расширяет этот адаптер и использует @EnableGlobalMethodSecurity .

Диаграмма классов, изображающая эту иерархию:

./b11f4caa037b65cae31ffc4fe0dea331.png

Теперь давайте настроим класс KeycloakSecurityConfig :

@KeycloakConfiguration
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.permitAll();
}
}

@KeycloakConfiguration определяет все необходимые аннотации для интеграции Keycloak с Spring Boot :

./12b12935d50635a98d783e6c7917f1e9.png

4.4. Добавление авторизации

Наконец, давайте воспользуемся аннотацией @RolesAllowed (часть JSR-250 ) для авторизации операций нашего веб-сервиса SOAP.

Учитывая это, давайте настроим наши методы с ролями доступа. Для этого воспользуемся аннотацией @RolesAllowed . Напомним, мы определили две разные роли, пользователя и администратора, в Keycloak. Давайте определим каждый из наших веб-сервисов с ролью:

@RolesAllowed("user")
@PayloadRoot(namespace = "http://www.foreach.com/springbootsoap/keycloak", localPart = "getProductDetailsRequest")
@ResponsePayload
public GetProductDetailsResponse getProductDetails(@RequestPayload GetProductDetailsRequest request) {
...
}
@RolesAllowed("admin")
@PayloadRoot(namespace = "http://www.foreach.com/springbootsoap/keycloak", localPart = "deleteProductRequest")
@ResponsePayload
public DeleteProductResponse deleteProduct(@RequestPayload DeleteProductRequest request) {
...
}

На этом мы завершили настройку.

5. Протестируйте приложение

5.1. Проверьте настройку

Теперь, когда приложение готово, давайте начнем тестировать наши веб-сервисы SOAP с помощью curl :

curl -d @request.xml -i -o -X POST --header 'Content-Type: text/xml' http://localhost:18080/ws/api/v1

В конце концов, если все настройки верны, мы получим ответ об отказе в доступе:

<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">Access is denied</faultstring>
</SOAP-ENV:Fault>

Как и ожидалось, Keycloak отклоняет запрос, поскольку запрос не содержит токена доступа.

5.2. Получение токена доступа

На этом этапе давайте получим токен доступа от Keycloak для доступа к нашим веб-сервисам SOAP. Как правило, поток включает в себя:

./0b645b38304848d07d7046b350634a0b.png

  • Во-первых, пользователь отправляет свои учетные данные в приложение
  • Приложение передает client-id и client-secret вместе с этими учетными данными на сервер Keycloak.
  • Наконец, Keycloak возвращает токен доступа, токен обновления и другие метаданные на основе учетных данных и ролей пользователя.

Keycloak предоставляет клиентам конечную точку токена для запроса токенов доступа . Обычно эта конечная точка имеет вид:

<ПРОТОКОЛ>://<HOST>:<PORT>/auth/realms/<REALM_NAME>/protocol/openid-connect/token

Например:

http://localhost:8080/auth/realms/foreach/protocol/openid-connect/токен

Теперь давайте получим токен доступа:

curl -L -X POST 'http://localhost:8080/auth/realms/foreach-soap-services/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=foreach-soap-services' \
--data-urlencode 'client_secret=14da6f9e-261f-489a-9bf0-1441e4a9ddc4' \
--data-urlencode 'username=janedoe' \
--data-urlencode 'password=password'

По сути, мы получаем токен доступа и токен обновления вместе с метаданными:

{
"access_token": "eyJh ...",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJh ...",
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "364b8f3e-34ff-4ca0-8895-bfbdb8b466d4",
"scope": "profile email"
}

Кроме того, настраиваемый ключ expires_in определяет время жизни этого токена. Например, указанный выше токен доступа истекает через 5 минут (300 секунд).

5.3. Вызов веб-сервиса с токеном доступа

В этом примере воспользуемся токеном доступа, который мы получили в предыдущем разделе. Давайте вызовем веб-службу SOAP с токеном доступа в качестве Bearer Token .

curl -d @request.xml -i -o -X POST -H 'Authorization: Bearer BwcYg94bGV9TLKH8i2Q' \
-H 'Content-Type: text/xml' http://localhost:18080/ws/api/v1

При правильном токене доступа ответ будет таким:

<ns2:getProductDetailsResponse xmlns:ns2="http://www.foreach.com/springbootsoap/keycloak">
<ns2:product>
<ns2:id>1</ns2:id>
...
</ns2:product>
</ns2:getProductDetailsResponse>

5.4. Авторизация

Напомним, что мы создали токен доступа для пользователя janedoe , у которого есть роль пользователя . С токеном доступа пользователя попробуем выполнить административные операции. То есть попробуем вызвать deleteProduct :

curl -d @request.xml -i -o -X POST -H 'Authorization: Bearer sSgGNZ3KbMMTQ' -H 'Content-Type: text/xml' \
http://localhost:18080/ws/api/v1

где содержимое request.xml :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:key="http://www.foreach.com/springbootsoap/keycloak">
<soapenv:Header/>
<soapenv:Body>
<key:deleteProductRequest>
<key:id>1</key:id>
</key:deleteProductRequest>
</soapenv:Body>
</soapenv:Envelope>

Поскольку пользователь не имеет права доступа к административным операциям, мы получаем отказ в доступе:

<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">Access is denied</faultstring>
</SOAP-ENV:Fault>

6. Заключение

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

Как всегда, полный исходный код доступен на GitHub .