Базовая проверка подлинности Фильтр и точка входа в систему аутентификации, фактически не использованная из spring запроса маркера oauth2
Я применил поток владельца ресурсов с помощью spring oauth2 на основе приложения образца spring sparklr и нескольких образцов, которые я нашел в Интернете. Я протестировал часть запроса токена с завитком, подобным этому, чтобы предоставить как клиентские, так и пользовательские учетные данные:
curl -v --data "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -X POST "http://localhost:8080/samplerestspringoauth2/oauth/token"
и он работает правильно, однако я сделал следующее замечание:
Хотя в соответствии с примерами, которые я видел, я использую фильтр BasicAuthentication, это не используется в процессе безопасности. Поскольку в запросе токена нет заголовка проверки подлинности, фильтр BasicAuthentication просто пропускает выполнение каких-либо проверок. ClientCredentialsTokenEndpointFilter и сервер аутентификации являются единственными, которые выполняют проверки безопасности во время запроса маркера. Заметив это и проверив его с помощью отладки, я попытался полностью удалить следующую часть:
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
из конфигурации. Но потом я получил предупреждение:
"Нет аутентификацииEntryPoint может быть установлена. у вас есть механизм входа, настроенный через пространство имен (например, form-login) или указать пользовательский AuthenticationEntryPoint с атрибут" entry-point-ref".
В качестве следующего шага я добавил точку входа-ref = "clientAuthenticationEntryPoint в пространстве имен http и избавился от предупреждения. Я протестировал приложение и проиграл правильно.
Однако, помимо вышесказанного, я также сделал следующее наблюдение во время отладки:
ClientCredentialsTokenEndpointFilter содержит свою собственную точку входа OAuth2AuthenticationEntryPoint внутри частной переменной и использует это при сбое из-за неправильных учетных данных клиента.
Поэтому не имеет значения, какую точку входа я указываю либо в базовом фильтре, либо в пространстве имен http. В конце ClientCredentialsTokenEndpointFilter будет использовать свой собственный OAuth2AuthenticationEntryPoint.
Подводя итоги, мои выводы выглядят следующим образом:
- Основной фильтр не используется и может быть удален, если мы укажем
конечной точки в пространстве имен HTTP.
- Указание либо основного
фильтра или конечной точки в пространстве имен http требуется только для
компилятор, чтобы остановить предупреждение. Они не имеют практического применения, и
используемая конечная точка жестко закодирована внутри
ClientCredentialsTokenEndpointFilter.
Ниже я поставил конфигурацию http и endpoint для запроса маркера для вашей справки. Я пропущу остальную конфигурацию, чтобы прочитать сообщение легко:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter"
before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
Я также предполагаю, что та же проблема возникает и в исходном приложении sparklr (который является spring oauth2 sample app) для запроса токена, который очень похож. Это можно найти в https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/main/webapp/WEB-INF/spring-servlet.xml, а соответствующая часть ниже:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/**" method="GET" access="ROLE_DENY" />
<intercept-url pattern="/**" method="PUT" access="ROLE_DENY" />
<intercept-url pattern="/**" method="DELETE" access="ROLE_DENY" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
Я ожидал бы spring oauth2 более разумно взаимодействовать с безопасностью spring вместо того, чтобы ставить ненужную и вводящую в заблуждение конфигурацию, и это заставляет меня думать, что я, возможно, что-то пропустил. Поскольку безопасность - это чувствительный аспект, я хотел бы поделиться этим с вами и спросить, правильно ли было мое заключение.
Ответы
Ответ 1
Параметр/oauth/token предоставляет два разных способа аутентификации клиентов, которые запрашивают токены:
-
Использование аутентификации HTTP-Basic (когда присутствует элемент "http-basic" )
Аутентификация обрабатывается с помощью org.springframework.security.web.authentication.www.BasicAuthenticationFilter и обрабатывает HTTP-заголовок "Авторизация", который содержит кодированные учетные данные клиента в базе64. Фильтр выполняет обработку только при наличии заголовка авторизации. Этот метод всегда проверяется первым. Точка входа, определенная на http-basic, будет вызываться только тогда, когда пользователь предоставил заголовок "Авторизация" с недопустимым контентом - почему вы не видите точку входа, вызванную в вашем отладчике, попробуйте установить HTTP-заголовок авторизации и точку останова получит удар.
-
Как определено в стандарте OAuth с использованием клиентских_параметров client_id и client_secret
Это обрабатывается с помощью org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter и по умолчанию использует точку входа, которая отправляет обратно WWW-Authenticate заголовок клиенту. Точка входа по умолчанию может быть настроена (существует метод setAuthenticationEntryPoint). Точка входа используется только при поставке параметра client_id.
Оба этих метода используют разные способы получения имени пользователя + пользователя, но проверяют его на тот же менеджер проверки подлинности.
Ошибка "Нет аутентификацииEntryPoint может быть установлена", которую вы наблюдаете при извлечении < http-basic > элемент исходит из Spring самой безопасности, а не из OAuth Extension. Причина в том, что Spring Security не может сказать, что в пользовательском фильтре ClientCredentialsTokenEndpointFilter уже настроена точка входа по умолчанию. И в конфигурации HTTP Spring Security всегда должна быть доступна хотя бы одна точка входа.
Итак, полная логика выглядит следующим образом:
- когда вы включаете заголовок "Авторизация" с недопустимыми учетными данными и < http-basic > элемент присутствует, система будет использовать точку входа, определенную на < http-basic > элемент. Если ни один не указан (атрибут entry-point-ref отсутствует), система автоматически создаст экземпляр BasicAuthenticationEntryPoint по умолчанию и будет использовать его.
- когда вы включаете параметры HTTP "client_id" и "client_secret" с недопустимыми учетными данными и настраиваемый фильтр clientCredentialsTokenEndpointFilter, система будет использовать точку входа, определенную в clientCredentialsTokenEndpointFilter bean (которая по умолчанию является экземпляром OAuth2AuthenticationEntryPoint)
- если нет ни заголовка "Авторизация", ни параметра "client_id", и конечная точка требует аутентификации ( "IS_AUTHENTICATED_FULLY" ), система будет использовать точку входа, определенную в < http entry-point-ref = "" > , если он присутствует, в противном случае он будет использовать точку входа, определенную на http-basic (как указано выше).
- в случае, если вы не укажете ни http-basic (или другой метод проверки подлинности по умолчанию, который признает Spring), ни точка входа по умолчанию с помощью < http entry-point-ref = " > , система не будет выполнена с" No AuthenticationEntryPoint можно установить", потому что для этого требуется хотя бы одна точка входа, и она не понимает, что там доступно внутри clientCredentialsTokenEndpointFilter.
Относительно ваших наблюдений:
→ Основной фильтр не используется и может быть удален, если мы укажем конечной точки в пространстве имен http.
> Это верно, если вы выполняете аутентификацию своих клиентов с помощью client_id + client_secret
→ Указание базового фильтра или конечной точки в пространстве имен http является необходимо только для компилятора, чтобы остановить предупреждение. У них нет практическое использование, а используемая конечная точка жестко закодирована внутри ClientCredentialsTokenEndpointFilter.
> Отчасти верно, поскольку точка входа будет использоваться в случае отсутствия client_id.
Конфигурация действительно запутывает (что частично связано с тем, что OAuth не является нативной частью Spring Security, а является расширением), но все эти настройки имеют смысл и используются в определенных ситуациях.
Изменения, внесенные вами, не имеют последствий для безопасности.