簡體   English   中英

用於2腳(客戶端憑據)OAuth2服務器的Spring-security上下文設置

[英]Spring-security context setup for 2-legged (client credentials) OAuth2 server

如果我想為一個客戶端保護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(UserDetailsS​​ervice)作為實現基本spring-security的一部分,以便對我們的數據庫保留帳戶和角色。


我真正得到的豆子是:

userApprovalHandler :為什么我需要在client_credentials流/ grant中獲得任何用戶批​​准? 似乎,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實現時必須使用它,為什么我現在要這樣做呢?

感謝閱讀! 希望有人能回答我的一些問題..

更新

我已將設置更新為當前工作狀態。 我現在可以使用客戶端憑據請求訪問令牌:

$ 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將由servlet-context初始化。 spring-context.xml本身只初始化bean。 (另外:我們的服務器也有一些視圖,因此所有其余資源都在/ rest下運行,因此url-pattern。但是:總是需要一個單獨的servlet和spring上下文。)

userApprovalHandler :如果您的系統中只有一個客戶端,我同意用戶不必批准它訪問他們的數據。

oauthAuthenticationEntryPoint :通常,如果身份驗證失敗,則響應類型為JSON。 文檔說“如果身份驗證失敗並且調用者要求特定的內容類型響應,則此入口點可以發送一個,以及標准的401狀態。”

clientCredentialsTokenEndpointFilter :發出訪問令牌分為兩步。 首先,將用戶發送到資源服務器進行身份驗證。 此重定向由客戶端驗證,理想情況下使用HTTP標頭(密鑰+密鑰)。 作為回報,客戶端獲取代碼,可以交換令牌。 您不直接交換密鑰+密鑰作為令牌,因為它不包含用戶的批准。

resourceServerFilter :我認為這樣做的目的是說明如果你有許多不同的資源,客戶可以訪問哪些資源。

accessDecisionManager :對於OAuth2,您需要一個ScopeVoter,因此默認的Manager不夠好。

通常 :如果您只有一個客戶端代表用戶訪問資源,那么可以考慮使用Digest而不是OAuth2? 如果您只想驗證客戶端(而不是用戶),那么OAuth2就太過分了。 OAuth2中的客戶端身份驗證與基於https的基本身份驗證完全相同。

REST客戶端和具有spring security ouath 2.0的用戶的oauth2的一個很好的例子: http ://www.e-zest.net/blog/rest-authentication-using-oauth-2-0-resource-owner-password-flow- 協議/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM