CXF实战之WS-Security(八)

Web-Security概述

WS-Security(Web服务安全)是一种提供在Web Service上应用安全的方法的网络传输协议,协议包含了关于如何在Web Service消息上保证完整性和机密性的规约。WS-Security描述了如何将签名和加密头加入SOAP消息。除此以外,还描述了如何在消息中加入安全令牌,包括二进制安全令牌,如X.509认证证书和Kerberos门票(ticket)。WS-Security将安全特性放入SOAP消息头中在应用层处理,这样协议保证了端到端的安全。

CXF中使用Web-Security

在CXF中实现服务端或者客户端的WS-Security,需要设置WSS4J拦截器。WS-Security规范支持多种令牌方式,UserNameToken头是其中一种方式。UserNameToken头是一种把用户米和密码或者密码摘要传到另一个端点的标准方式。

服务端

在配置文件pom.xml中添加WS-Security引用。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.rvhogroupId>
    <artifactId>cxfserversartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <packaging>warpackaging>

    <properties>
        
        <cxf.version>3.1.1cxf.version>
        
        <spring.version>4.1.7.RELEASEspring.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aopartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aspectsartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webartifactId>
            <version>${spring.version}version>
        dependency>
        

        
        <dependency>
            <groupId>org.apache.cxfgroupId>
            <artifactId>cxf-rt-frontend-jaxwsartifactId>
            <version>${cxf.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.cxfgroupId>
            <artifactId>cxf-rt-frontend-jaxrsartifactId>
            <version>${cxf.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.cxfgroupId>
            <artifactId>cxf-rt-transports-httpartifactId>
            <version>${cxf.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.cxfgroupId>
            <artifactId>cxf-rt-ws-securityartifactId>
            <version>${cxf.version}version>
        dependency>
        
        
        
    dependencies>
project>

服务端回调函数ServerPasswordCallbackHandler,校验客户端请求是否合法,合法就放行,否则拒绝执行任何操作。

package com.rvho.cxfserver.callback;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.wss4j.common.ext.WSPasswordCallback;

public class ServerPasswordCallbackHandler implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        if (pc.getIdentifier().equals("admin")) {
            //设置密码
            //这个密码和客户端发送的密码进行比较
            //如果和客户端不同将抛出org.apache.ws.security.WSSecurityException
            pc.setPassword("123");
        }
    }

}

服务端通过输入拦截器WSS4JInInterceptor实现WS-Security的校验,如果服务端集成了Spring,WSS4JInInterceptor配置如下。


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:soap="http://cxf.apache.org/bindings/soap"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd 
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

    
    <bean id="serverPasswordCallback" class="com.rvho.cxfserver.callback.ServerPasswordCallbackHandler">bean>

    <jaxws:endpoint id="helloWSEndpoint" implementor="#helloWS" address="/hello">
        <jaxws:inInterceptors>
            
            <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
                
                <constructor-arg>
                    <map>
                        <entry key="action" value="UsernameToken"/>
                        
                        <entry key="passwordType" value="PasswordText"/>
                        <entry key="passwordCallbackRef">
                            
                            <ref bean="serverPasswordCallback"/>
                        entry>
                    map>
                constructor-arg>
            bean>
            <bean class="org.apache.cxf.interceptor.LoggingInInterceptor">bean>
        jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor">bean>
        jaxws:outInterceptors>
    jaxws:endpoint>
beans>

如果服务端通过代码方式发布服务,可以用API添加。

JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setServiceClass(HelloWS.class);
factory.setAddress("http://localhost:8280/cxfservers/services/hello");
factory.setServiceBean(new HelloWSImpl());

//WS-Security输入拦截器
Map inProps = new HashMap();
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallbackHandler.class.getName());

factory.getInInterceptors().add(new WSS4JInInterceptor(inProps));
factory.getInInterceptors().add(new LoggingInInterceptor());

factory.create();

客户端

客户端回调函数ServerPasswordCallbackHandler,回调函数在发请求时添加密码。

package com.rvho.cxfclient.callback;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.wss4j.common.ext.WSPasswordCallback;

public class ClientPasswordCallbackHandler implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        pc.setPassword("123");
    }

}

客户端请求

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloWS.class);
factory.setAddress("http://localhost:8280/cxfservers/services/hello");
factory.getInInterceptors().add(new org.apache.cxf.interceptor.LoggingInInterceptor());

//WS-Security输出拦截器
Map outProps = new HashMap();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
//添加用户名
outProps.put(WSHandlerConstants.USER, "admin");
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

factory.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));
factory.getOutInterceptors().add(new com.rvho.cxfclient.interceptor.AuthAddInterceptor());
factory.getOutInterceptors().add(new org.apache.cxf.interceptor.LoggingOutInterceptor());

HelloWS helloWS = factory.create(HelloWS.class);
String welcome = helloWS.welcome("[email protected]");
System.out.println(welcome);

客户端和服务端数据格式

八月 03, 2015 2:31:51 下午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8280/cxfservers/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:UsernameToken wsu:Id="UsernameToken-581191d1-7dcb-479b-a739-0ebb063d740f"><wsse:Username>adminwsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123wsse:Password>wsse:UsernameToken>wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>adminname><password>adminpassword>auth>soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>[email protected]name>ns2:welcome>soap:Body>soap:Envelope>
--------------------------------------
八月 03, 2015 2:31:51 下午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Inbound Message
----------------------------
ID: 1
Address: http://localhost:8280/cxfservers/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[847], content-type=[text/xml; charset=UTF-8], Host=[localhost:8280], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 3.1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:UsernameToken wsu:Id="UsernameToken-581191d1-7dcb-479b-a739-0ebb063d740f"><wsse:Username>adminwsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123wsse:Password>wsse:UsernameToken>wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>adminname><password>adminpassword>auth>soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>[email protected]name>ns2:welcome>soap:Body>soap:Envelope>
--------------------------------------

你可能感兴趣的:(CXF,WebService)