加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

CXF实战之WS-Security(八)

发布时间:2020-12-16 22:42:37 所属栏目:安全 来源:网络整理
导读:Web-Security概述 WS-Security(Web服务安全)是一种提供在Web Service上应用安全的方法的网络传输协议,协议包含了关于如何在Web Service消息上保证完整性和机密性的规约。WS-Security描述了如何将签名和加密头加入SOAP消息。除此以外,还描述了如何在消息中

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.0</modelVersion>
    <groupId>com.rvho</groupId>
    <artifactId>cxfservers</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <!-- CXF版本 -->
        <cxf.version>3.1.1</cxf.version>
        <!-- Spring版本 -->
        <spring.version>4.1.7.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- End Spring -->

        <!-- CXF -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-ws-security</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <!--如果用tomcat发布,不需要引用jetty-->
        <!-- <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> -->
        <!-- End CXF -->
    </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配置如下。

<?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: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>
            <!-- WS-Security拦截器 -->
            <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
                <!-- 拦截器的构造函数参数 -->
                <constructor-arg>
                    <map>
                        <entry key="action" value="UsernameToken"/>
                        <!-- 密码类型,PasswordText表示明文 -->
                        <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<String,Object> inProps = new HashMap<String,Object>();
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<String,Object> outProps = new HashMap<String,Object>();
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("accountwcx@qq.com");
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>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123</wsse:Password></wsse:UsernameToken></wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>admin</name><password>admin</password></auth></soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>accountwcx@qq.com</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>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123</wsse:Password></wsse:UsernameToken></wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>admin</name><password>admin</password></auth></soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>accountwcx@qq.com</name></ns2:welcome></soap:Body></soap:Envelope>
--------------------------------------

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读