Статьи

Базовая и дайджест-аутентификация для службы RESTful с Spring Security 3.1, часть 6

Это шестая из серии статей о настройке защищенного веб-сервиса RESTful с использованием Spring 3.1 и Spring Security 3.1. В предыдущей статье была представлена ​​защита в контексте службы RESTful с использованием аутентификации на основе форм. В этой статье основное внимание будет уделено настройке базовой и дайджест- аутентификации и настройке обоих протоколов для одного и того же сопоставления URI API с использованием Spring Security 3.1.

Серия «Отдых с весной»:

Конфигурация базовой аутентификации

В третьей части этой серии конфигурация Spring Security была выполнена с использованием аутентификации на основе форм, которая на самом деле не идеальна для службы RESTful. Чтобы начать настройку базовой аутентификации, сначала мы удаляем старую настраиваемую точку входа и фильтруем из основного <http> элемента безопасности:

<http create-session="stateless">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />
   
   <http-basic />
</http>

Обратите внимание, что поддержка базовой аутентификации была добавлена ​​с помощью одной строки конфигурации — <http-basic /> -, которая обрабатывает создание и подключение как BasicAuthenticationFilter, так и BasicAuthenticationEntryPoint .

Удовлетворение ограничения без сохранения состояния — избавление от сеансов

Одним из основных ограничений архитектурного стиля RESTful является то, что клиент-серверная связь полностью не имеет состояния , как говорится в оригинальной диссертации :

    5.1.3 Без гражданства

Затем мы добавим ограничение к взаимодействию клиент-сервер: связь должна быть без состояния по своей природе, как в стиле клиент-сервер без состояния (CSS) в разделе 3.4.3 (рисунок 5-3), так что каждый запрос от клиента к Сервер должен содержать всю информацию, необходимую для понимания запроса, и не может использовать какой-либо сохраненный контекст на сервере. Поэтому состояние сеанса полностью сохраняется на клиенте .

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

Настройка дайджест-аутентификации

Начиная с предыдущей конфигурации, фильтр и точка входа, необходимые для настройки дайджест-аутентификации, будут определены как bean-компоненты. Затем точка входа в дайджест заменит ту, которая была создана <http-basic> за кулисами. Наконец, пользовательский дайджест-фильтр будет введен в цепочку фильтров безопасности с использованием семантики после пространства имен безопасности, чтобы расположить его непосредственно после фильтра базовой аутентификации.

<http create-session="stateless" entry-point-ref="digestEntryPoint">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />
   
   <http-basic />
   <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>
   
<beans:bean id="digestFilter" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
   <beans:property name="userDetailsService" ref="userService" />
   <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" />
</beans:bean>
   
<beans:bean id="digestEntryPoint" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
   <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/>
   <beans:property name="key" value="acegi" />
</beans:bean>

<authentication-manager>
   <authentication-provider>
      <user-service id="userService">
         <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
         <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>

К сожалению, в пространстве имен безопасности не поддерживается автоматическая настройка дайджест-проверки подлинности, так как базовая проверка подлинности может быть настроена с помощью <http-basic> . Из-за этого необходимые компоненты должны были быть определены и подключены вручную в конфигурацию безопасности.

Поддержка обоих протоколов аутентификации в одном сервисе RESTful

Обычная или дайджест-проверка подлинности может быть легко реализована в Spring Security 3.x; он поддерживает оба из них для одного и того же веб-сервиса RESTful, в тех же отображениях URI, что вводит новый уровень сложности в настройку и тестирование сервиса.

Анонимный запрос

При использовании как базового, так и дайджест-фильтров в цепочке безопасности способ, которым анонимный запрос — запрос, не содержащий учетных данных аутентификации ( заголовок HTTP авторизации ), — обрабатывается Spring Security: два фильтра аутентификации не найдут учетные данные и продолжат выполнение Цепочка фильтров. Затем, видя , как запрос не прошел проверку подлинности, AccessDeniedException брошено и попал в ExceptionTranslationFilter , который начинается точкой входа дайджеста, побуждая клиент для учетных данных.

Обязанности как основного, так и дайджест-фильтров очень узки — они будут продолжать выполнять цепочку фильтров безопасности, если не смогут определить тип учетных данных для аутентификации в запросе. Именно поэтому Spring Security может быть гибко настроен с поддержкой нескольких протоколов аутентификации на одном и том же URI.

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

Запрос с учетными данными аутентификации

Запрос с учетными данными для обычной проверки подлинности будет идентифицирован Authorization заголовка , начиная с префиксом «Basic» . При обработке такого запроса учетные данные будут декодированы в базовом фильтре аутентификации, и запрос будет авторизован. Аналогично, запрос с учетными данными для дайджест-аутентификации будет использовать префикс «Дайджест»   для своего заголовка авторизации .

Тестирование обоих сценариев

Тесты будут использовать REST-сервис, создав новый ресурс после аутентификации с помощью basic или digest:

@Test
public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( this.paths.getFooURL() );
   
   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}
@Test
public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( this.paths.getFooURL() );
   
   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}

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

Вывод

В этой статье рассказывается о настройке и реализации базовой и дайджест-проверки подлинности для службы RESTful, использующей в основном поддержку пространства имен Spring Security 3.0, а также некоторые новые функции, добавленные в Spring Security 3.1. В следующих статьях я остановлюсь на аутентификации OAuth. В то же время, проверьте проект GitHub .

Из серии ОТДЫХ с весны .