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
для нашего потока аутентификации:
Наконец, нажмите « Сохранить
», а затем перейдите на вкладку « Учетные данные
» и запишите секрет.
Следовательно, он нам понадобится как часть конфигурации Spring Boot.
3.2. Пользователи и роли
Далее создадим двух пользователей и назначим им роли и пароли:
Во-первых, давайте создадим роли администратора
и пользователя.
Keycloak позволяет нам создавать два типа ролей — роли Realm
и клиентские роли
. Однако сначала давайте создадим клиентские роли
.
Нажмите « Клиенты»,
выберите клиента и перейдите на вкладку «Роли
». Затем создайте две роли, администратора
и пользователя:
Хотя Keycloak может извлекать пользователей из LDAP или AD (Active Directory), для простоты давайте вручную настроим пользователей и назначим им роли.
Создадим двух пользователей. Сначала мы нажимаем « Пользователи»,
затем «Добавить пользователя
» :
Теперь давайте распределим роли между пользователями.
Снова нажмите « Пользователи
», выберите пользователя и нажмите « Изменить»,
затем перейдите на вкладку « Сопоставление ролей
», выберите клиента из « Роли клиента»
и выберите роль в « Доступных ролях».
Назначим роль администратора
одному пользователю, а роль пользователя
— другому:
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.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. Включить глобальную безопасность метода
Помимо предыдущих конфигураций, нам нужно указать ограничения безопасности для защиты наших веб-сервисов. Эти ограничения позволяют ограничить несанкционированный доступ. Например, мы должны ограничить пользователя
от действий администратора .
Существует два способа установки ограничений:
- Объявите
ограничения
безопасности иколлекции безопасности
в файле конфигурации приложения. - Безопасность на уровне метода с использованием
@EnableGlobalMethodSecurity
.
Для веб-служб SOAP ограничения безопасности
не обеспечивают точного контроля. Более того, объявление этих ограничений слишком многословно.
Впредь давайте использовать возможности @EnableGlobalMethodSecurity
для защиты операций веб-службы SOAP.
4.3. Определение KeycloakWebSecurityConfigurerAdapter
KeycloakWebSecurityConfigurerAdapter
— необязательный удобный класс, расширяющий WebSecurityConfigurerAdapter
и упрощающий настройку контекста безопасности . Далее давайте определим класс KeycloakSecurityConfig
, который расширяет этот адаптер и использует @EnableGlobalMethodSecurity
.
Диаграмма классов, изображающая эту иерархию:
Теперь давайте настроим класс 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 :
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. Как правило, поток включает в себя:
- Во-первых, пользователь отправляет свои учетные данные в приложение
- Приложение передает
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 .