使用Spring Security + WSO2 Identity Server的OAuth 2.0

芋头 :

我正在开发一个Web应用程序,以公开由OAuth 2.0保护的许多RESTful服务。这是计划的体系结构:

1- OAuth授权提供者: WSO2身份服务器(IS)

2- OAuth资源服务器:使用以下技术的Java Web应用程序:

  • 泽西岛(实现和公开Web服务)
  • Spring Security(实现OAuth资源服务器部分)

我已经看到了几个有关如何使用WSO2 IS作为授权服务器+ WSO2 ESB作为资源服务器来保护RESTful服务的示例(ex1ex2ex3等)。这不是我所需要的。

不幸的是,授权服务器和资源服务器之间的交互超出了OAuth2 RFC的范围因此,我找不到更多的外观。

这是我的问题:

  • 如何配置Spring Security充当资源服务器,以验证由外部OAuth提供程序(例如WSO2 IS)发出的访问令牌?
  • 资源服务器应如何识别给定访问令牌的范围?
  • 如何识别从WSO2 IS获得访问令牌的资源所有者?

谢谢

芋头 :

经过研究后,我想出了方法。该解决方案分为两个主要部分:WSO2 IS配置资源服务器配置

基本方案如下:

1-客户端(例如,移动应用程序)通过向资源服务器(在我的情况下为Java Web应用程序)发送请求来消耗安全资源(例如,Web服务)。

2-资源服务器验证请求中的“授权”标头并提取访问令牌。

3-资源服务器通过将访问令牌发送到授权服务器(WSO2 IS)来验证访问令牌。

4-授权服务器以验证响应进行响应。

5-资源服务器验证响应并决定是授予还是拒绝对所请求资源的访问。

在我的演示中,我使用了WSO2 IS 5.0.0和Spring security 3.1.0。


1- WSO2 IS配置

WSO2 IS将充当授权服务器因此,应将其配置为支持OAuth 2.0。为此,应添加新的服务提供商并将其配置如下:

(a)登录到WSO2 IS管理控制台。

(b)添加一个新的服务提供商,并为其提供名称和描述。

服务提供商配置:屏幕快照1

(c)在“ 入站验证配置 ” >>“ OAuth / OpenID连接配置 ” >>“ 配置”下

(d)如以下屏幕截图所示配置OAuth 2.0提供程序,然后点击添加我们需要密码映射到交付式资源所有者密码凭证交付式。最适合我的情况(确保Web服务安全)。

服务提供商配置:屏幕快照2

(e) Under OAuth/OpenID Connect Configuration, you'll find OAuth Client Key and OAuth Client Secret generated. They are used along with username, password, and scope to generate access tokens.


2- Resources Server Configuration

As mentioned earlier, the demo Java web application will act as Resources server and client at the same time. To act as resources server, Spring security needs to know how to validate access tokens. So, a token services implementation should be provided.

(a) Configure spring to act as resources server. Here is a sample configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:security="http://www.springframework.org/schema/security"
   xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd
    http://www.springframework.org/schema/security/oauth2
    http://www.springframework.org/schema/security/spring-security-oauth2.xsd">

    <bean id="tokenServices" class="com.example.security.oauth2.wso2.TokenServiceWSO2" />

    <bean id="authenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint" />

    <security:authentication-manager alias="authenticationManager" />

    <oauth2:resource-server id="resourcesServerFilter" token-services-ref="tokenServices" />

    <security:http pattern="/services/**" create-session="stateless" entry-point-ref="authenticationEntryPoint" >
        <security:anonymous enabled="false" />
        <security:custom-filter ref="resourcesServerFilter" before="PRE_AUTH_FILTER" />
        <security:intercept-url pattern="/services/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    </security:http>
</beans>

Here, a resource-server that uses a token services implementation TokenServiceWSO2 is configured. The resource-server tag is actually transformed to a security filter. An interception pattern is added to "/services/**" and the resources sever filter is added to the chain.

(b) Implement OAuth 2.0 token services ResourceServerTokenServices. The implementation will take an access token as an input, pass it to OAuth2TokenValidationService service exposed by WSO2 IS, validate the response and return a processed object containing the basic data about the token's issuer, validity, scope, corresponding JWT token, ...

public class TokenServiceWSO2 implements ResourceServerTokenServices {

    @Autowired
    TokenValidatorWSO2 tokenValidatorWSO2;

    public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {

        try {
            TokenValidationResponse validationResponse = tokenValidatorWSO2.validateAccessToken(accessToken);
            OAuth2Request oAuth2Request = new OAuth2Request(null, null, null, true, validationResponse.getScope(), null, null, null,null);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(validationResponse.getAuthorizedUserIdentifier(), null, null);
            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
            return oAuth2Authentication;
        } catch (ApplicationException ex) {
            // Handle exception
        }
    }

    public OAuth2AccessToken readAccessToken(String accessToken) {
        // TODO Add implementation
    }

}

TokenValidatorWSO2 class implements the logic to call WSO2 IS's web service OAuth2TokenValidationService

@Component
public class TokenValidatorWSO2 implements OAuth2TokenValidator{

    private static final Logger logger = Logger.getLogger(TokenValidatorWSO2.class);

    @Value("${server_url}")
    private String serverUrl;

    @Value("${validation_service_name}")
    private String validationServiceName;

    @Value("${comsumer_key}")
    private String consumerKey;

    @Value("${admin_username}")
    private String adminUsername;

    @Value("${admin_password}")
    private String adminPassword;

    private OAuth2TokenValidationServiceStub stub;

    private static final int TIMEOUT_IN_MILLIS = 15 * 60 * 1000;

    public TokenValidationResponse validateAccessToken(String accessToken) throws ApplicationException {
        logger.debug("validateAccessToken(String) - start");

        if(stub == null) {
            initializeValidationService();
        }

        OAuth2TokenValidationRequestDTO  oauthRequest;
        TokenValidationResponse validationResponse;
        OAuth2TokenValidationRequestDTO_OAuth2AccessToken oAuth2AccessToken;

        try {
            oauthRequest = new OAuth2TokenValidationRequestDTO();
            oAuth2AccessToken = new OAuth2TokenValidationRequestDTO_OAuth2AccessToken();
            oAuth2AccessToken.setIdentifier(accessToken);
            oAuth2AccessToken.setTokenType("bearer");
            oauthRequest.setAccessToken(oAuth2AccessToken);
            OAuth2TokenValidationResponseDTO response = stub.validate(oauthRequest);

            if(!response.getValid()) {
                throw new ApplicationException("Invalid access token");
            }

            validationResponse = new TokenValidationResponse();
            validationResponse.setAuthorizedUserIdentifier(response.getAuthorizedUser());
            validationResponse.setJwtToken(response.getAuthorizationContextToken().getTokenString());
            validationResponse.setScope(new LinkedHashSet<String>(Arrays.asList(response.getScope())));
            validationResponse.setValid(response.getValid());

        } catch(Exception ex) {
            logger.error("validateAccessToken() - Error when validating WSO2 token, Exception: {}", ex);
        }

        logger.debug("validateAccessToken(String) - end");
        return validationResponse;
    }

    private void initializeValidationService() throws ApplicationException {
        try {
            String serviceURL = serverUrl + validationServiceName;
            stub = new OAuth2TokenValidationServiceStub(null, serviceURL);
            CarbonUtils.setBasicAccessSecurityHeaders(adminUsername, adminPassword, true, stub._getServiceClient());
            ServiceClient client = stub._getServiceClient();
            Options options = client.getOptions();
            options.setTimeOutInMilliSeconds(TIMEOUT_IN_MILLIS);
            options.setProperty(HTTPConstants.SO_TIMEOUT, TIMEOUT_IN_MILLIS);
            options.setProperty(HTTPConstants.CONNECTION_TIMEOUT, TIMEOUT_IN_MILLIS);
            options.setCallTransportCleanup(true);
            options.setManageSession(true);
        } catch(AxisFault ex) {
            // Handle exception
        }
    }
}

TokenValidationResponse class holds the basic data returned in token validation response.

public class TokenValidationResponse {

    private String jwtToken;
    private boolean valid;
    private Set<String> scope;
    private String authorizedUserIdentifier;

    public String getJwtToken() {
        return jwtToken;
    }

    public void setJwtToken(String jwtToken) {
        this.jwtToken = jwtToken;
    }

    public boolean isValid() {
        return valid;
    }

    public void setValid(boolean valid) {
        this.valid = valid;
    }

    public Set<String> getScope() {
        return scope;
    }

    public void setScope(Set<String> scope) {
        this.scope = scope;
    }

    public String getAuthorizedUserIdentifier() {
        return authorizedUserIdentifier;
    }

    public void setAuthorizedUserIdentifier(String authorizedUserIdentifier) {
        this.authorizedUserIdentifier = authorizedUserIdentifier;
    }
}

3- Client Application Configuration

The last step is to configure the resources to be protected by OAuth 2.0. Basically, configure the web services to be secured with a root URL path "/services/**". In my demo, I used Jersey.


4- Test The Client Application

The last step is to consume the secured web services. This is done by adding Authorization header to the request with value " ", for example "bearer 7fbd71c5b28fdf0bdb922b07915c4d5".


PS所描述的示例仅用于澄清目的。它可能会缺少某些实现,异常处理等。。。请进一步评论。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Spring SAML与WSO2 Identity Server集成,未重新协调SAML消息ID

如何自定义所有WSO2 Identity Server登录相关页面

使用WSO2 Identity Server管理外部自定义权限吗?

WSO2 Identity Server 5.1.0在SAML响应中未返回用户声明

WSO2 Identity Server的用户和租户

WSO2 Identity Server用户身份验证的HTTP请求

有什么方法可以在WSO2 Identity Server中加密用户名?

WSO2 Identity Server 5.9.0 oAuth2配置类型

WSO2 Identity Server与ADFS Server集成时抛出NullpointerException

使用WSO2 Identity Server和WSO2 API Manager保护后端

WSO2 Identity Server升级

为WSO2 Identity Server部署自定义密码策略文件

如何使用Identity Server登录WSO2解决方案

基于SAML / XACML的WSO2 Identity Server访问控制

WSO2 Identity Server在用户存储,策略管理等中看不到选项

WSO2 Identity Server中的SCIM服务提供商

WSO2 Identity Server中的SAML请求-响应处理

使用WSO2 Identity Server的SAML2.0 SSO?

集成bonita和wso2 Identity Server

WSO2 Identity Server将用户设置为“非活动”

在wso2 Identity Server中使用示例代码创建用户

WSO2 Identity Server未返回带有OAuth / OpenID的请求的声明

Spring Security WSO2 IS集成-弄清楚如何分配权限/自定义wso2令牌

使用WSO2 Identity Server 5.1进行单点登录

WSO2 API Manager使用Identity Server存储访问

wso2 Identity Server-无法删除租户

用于会话管理的 WSO2 Identity Server 5.0.0 Api

如何配置 WSO2 API Manager 2.1.0 以使用 Identity Server 5.4.1

WSO2 sh wso2server.sh -Dmigrate -Dcomponent=identity 没有运行迁移脚本