1 つのクライアントの REST サーバーを保護する場合、spring-security OAuth2 の最小設定は何ですか? 不要なセットアップを使用したり、不要な Bean を実装したりしたくありません。spring-security + OAuth2 の「簡単な」チュートリアル/例が既にあるのではないでしょうか? (期待しすぎないように気をつけていますが)
私の現在の作業セットアップ (sparklr コンテキストからのコピー+過去+wtf での作業) は多すぎるように感じます:
<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) を既に実装しています。
私が実際に得られない豆は次のとおりです。
userApprovalHandler : client_credentials フロー/グラントでユーザーの承認が必要なのはなぜですか? どうやら、sparklr はデフォルトをオーバーライドして、TokenServicesUserApprovalHandler
1 つのクライアントを自動承認するようです。信頼できるクライアントとサーバーの間の通信のためにも、これを行う必要がありますか?
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 実装をセットアップするときにこれを使用する必要があったことを覚えていません。なぜ今そうする必要があるのでしょうか?
読んでくれてありがとう!誰かが私の質問のいくつかに答えてくれることを願っています..
アップデート
セットアップを現在の動作状態に更新しました。クライアント資格情報を使用してアクセス トークンを要求できるようになりました。
$ 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 通信機能を要求パラメーターと統合することだけだったからです。
すべてのスプリング セキュリティ セットアップについて詳しく知ることも役立ちますが、ドキュメントは非常に薄いです..
編集
春のセキュリティ構成を現在の状態に更新しました。また、ここに 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 自体は、Bean のみを初期化します。(また: 私たちのサーバーにはいくつかのビューもあるため、すべての残りのリソースは /rest の下で実行されるため、url-pattern になります。しかし: 個別のサーブレットとスプリング コンテキストが常に必要です。)