Базовая проверка подлинности Фильтр и точка входа в систему аутентификации, фактически не использованная из 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, а является расширением), но все эти настройки имеют смысл и используются в определенных ситуациях.

Изменения, внесенные вами, не имеют последствий для безопасности.