Какая минимальная настройка для spring -security OAuth2, если я хочу защитить сервер REST для одного клиента? Я не хочу использовать ненужную настройку или внедрять ненужные beans. Может быть, есть "легкий" учебник/пример, который уже существует для spring -security + OAuth2? (Хотя я стараюсь не слишком надеяться на это)
Моя текущая рабочая настройка (работа с копией + прошлое + wtf из контекста sparklr) выглядит слишком много:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:client-credentials />
</oauth:authorization-server>
<sec:authentication-manager alias="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<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" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<oauth:resource-server id="resourceServerFilter"
resource-id="rest_server" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="the_client" authorized-grant-types="client_credentials"
authorities="ROLE_RESTREAD" secret="1234567890" />
</oauth:client-details-service>
<http pattern="/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/rest/**" access="ROLE_RESTREAD" method="GET" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="false" />
<property name="clientDetailsService" ref="clientDetails" />
<property name="accessTokenValiditySeconds" value="400000" />
<property name="refreshTokenValiditySeconds" value="0" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="theRealm" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="theRealm/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
Я уже реализовал authenticationManager (UserDetailsService) как часть реализации базовой spring -security, чтобы учетные записи и роли сохранялись в нашей базе данных.
beans Я действительно не понимаю:
userApprovalHandler. Зачем мне нужно одобрение любого пользователя в потоке/гранте client_credentials? Кажется, sparklr переопределяет значение по умолчанию TokenServicesUserApprovalHandler
для автоматического утверждения одного клиента. Нужно ли мне это делать и для связи между моими доверенными клиентами и сервером?
oauthAuthenticationEntryPoint: все sparklr делает следующее:
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="sparklr2" />
</bean>
Что это должно было сделать?
clientCredentialsTokenEndpointFilter В нем говорится, что я должен включить это только в том случае, если я хочу пройти аутентификацию через параметры запроса. Так что я имею в виду именно это: Отправить запрос GET (?) На мой сервер с этим секретом и получить токен и с этим доступом к токену ресурсы? Поэтому я думаю, что запрос на токен должен содержать секрет как параметр запроса.?
resourceServerFilter Мне кажется, что это указывает на отдельный сервер ресурсов? Как это применимо, если мои ресурсы находятся на том же сервере, что и поставщик проверки подлинности?
AccessDecisionManager Я не помню, чтобы использовать это при настройке моей пользовательской реализации spring -security, почему я хочу сделать это сейчас?
Спасибо, что прочитали! Надеюсь, кто-то может ответить на несколько моих вопросов.
Update
Я обновил настройку до текущего рабочего состояния. Теперь я могу запросить токен доступа с учетными данными клиента:
$ curl -X -v -d 'client_id=the_client&client_secret=secret&grant_type=client_credentials' -X POST "http://localhost:9090/our-server/oauth/token"
и использовать этот токен для доступа к защищенным ресурсам:
$ curl -H "Authorization: Bearer fdashuds-5432fsd5-sdt5s5d-sd5" "http://localhost:9090/our-server/rest/social/content/posts"
По-прежнему чувствуется много настроек, и мои вопросы остаются. Также мне интересно, правильно ли это для обеспечения связи между надежным клиентом и сервером REST в целом.
Он также по-прежнему чувствует, что первоначальный запрос для токена не защищен, за исключением случаев, когда он выполняется через https, но этого будет достаточно?
И что же касается самого токена, должен ли я дать ему долгую жизнь и сохранить его на клиенте? что в любом случае означало бы уловить исключение срока действия токена и затем запросить новый. Или я должен выполнить рукопожатие для каждого запроса? Как насчет обновления токена? Я думаю, что я где-то читал, что токен обновления не защищен для типа полномочий учетных данных клиента..? Нужно ли отправлять токен в виде заголовка HTTP или я могу его изменить? Я не хочу использовать стек клиента spring -security для нашего клиента, поскольку он имеет довольно устаревшую настройку (jboss 5), и все, что мы делали до сих пор, заключалось в интеграции возможностей связи REST с параметрами запроса.
Это также поможет узнать больше обо всех настройках spring -security, но документация довольно тонкая.
ИЗМЕНИТЬ
Обновлена конфигурация безопасности spring для нашего текущего состояния. Кроме того, здесь наш web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>the-display-name</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>base.package.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/servlet-context.xml
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.appServlet</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Примечание. spring -security-context.xml сверху будет инициализирован сервлет-контекстом. Сам spring -context.xml инициализирует beans. (Также: у нашего сервера также есть несколько представлений, поэтому все ресурсы ресурсов работают под /rest, следовательно, с шаблоном url. Но: всегда необходимо иметь отдельный сервлет и контекст spring.)