分享

cxf ws

 昵称16257403 2014-03-13

以下文章为 cxf 官方 google 翻译,英文好的朋友可以直接看原文:

http://cxf./docs/ws-security.html

 

WS - Security提供了手段,以确保您的服务,如HTTPS传输级别的协议超出。 通过一些标准,如XML加密,并在WS - Security标准中定义的头,它可以让你:

  • 在服务之间传递的身份验证令牌
  • 对信息进行加密或部分消息
  • 登录消息
  • 时间戳消息

目前,CXF的实现结合的WS - Security WSS4J 要使用的集成,你需要配置这些拦截器,并将它们添加到您的服务和/或客户。

 

加密和签名的概述

WS - Security的公共/私人密钥加密技术的大量使用。 要真正了解如何配置的WS - Security,它是有用的 - 如果没有必要 - 要了解这些基础知识。 维基百科在此有一个极好的入门 ,但我们会尝试总结了相关的基础知识(此内容是维基百科的内容修改后的版本.. )

与公共密钥加密,用户有一对公钥和私钥。 这些都是用一个大素数和一个关键功能。


键是有关数学的,但不能从一个派生。 与这些键,我们可以对信息进行加密。 例如,如果Bob想将消息发送给Alice,他可以用她的公钥加密消息。 然后,Alice可以解密此消息使用她的私钥。 只有Alice可以解密此消息,因为她是用私钥只有一个。



 信息也可以签署。 这使您可以确保消息的真实性。 如果Alice想将消息发送给Bob,Bob想确保它是从Alice,Alice可以使用自己的私钥来签名消息。 然后,Bob可以确认该消息是从Alice用她的公钥。


配置WSS4J拦截

为了使内CXF的WS - Security的服务器或客户端,你需要成立WSS4J拦截。 您可以通过API独立的Web服务或通过Spring XML配置servlet的主办。 本节将提供一个概述如何做到这一点,以下各节将进入更详细的拦截器配置为特定的安全行动。

重要的是要注意:

  1. 如果你是使用CXF 2.0.x的,你必须添加SAAJ(IN / OUT)拦截器,如果你使用WS - Security(自动为你这样做是CXF的2.1起)。 这些使创建为每个请求/响应的DOM树。 WS - Security的支持库需要DOM树。
  2. Web服务提供者可能并不需要和WS -安全拦截。 例如,如果你只是需要传入消息的签名,Web服务提供者将只需要传入WSS4J拦截的SOAP客户端只需要传出。

 

通过API添加拦截器

在服务器端,你将要添加的拦截您的CXF的端点。 如果你使用的JAX - WS的API发布您的服务,你可以得到你这样的CXF的端点:

 

Java代码 复制代码 收藏代码
  1. import org.apache.cxf.endpoint.Endpoint;   
  2. import org.apache.cxf.jaxws.EndpointImpl;   
  3.   
  4. EndpointImpl jaxWsEndpoint = (EndpointImpl) Endpoint.publish("http://host/service",    
  5.     myServiceImpl);   
  6. Endpoint cxfEndpoint = jaxWsEndpoint.getServer().getEndpoint();  

 

如果您使用过的(JAXWS)ServerFactoryBean,你可以简单地通过服务器对象的访问:

 

Java代码 复制代码 收藏代码
  1. import org.apache.cxf.endpoint.Endpoint;   
  2. import org.apache.cxf.endpoint.Server;   
  3. import org.apache.cxf.frontend.ServerFactoryBean;   
  4.   
  5. ServerFactoryBean factory = ...;   
  6. ...   
  7. Server server = factory.create();   
  8. Endpoint cxfEndpoint = server.getEndpoint();  

 

 在客户端,您可以得到一个参考CXF的端点使用ClientProxy帮手:

 

Java代码 复制代码 收藏代码
  1. import org.apache.cxf.frontend.ClientProxy;   
  2. ...   
  3.   
  4. GreeterService gs = new GreeterService();   
  5. Greeter greeter = gs.getGreeterPort();   
  6. ...   
  7. org.apache.cxf.endpoint.Client client = ClientProxy.getClient(greeter);   
  8. org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();  

 

 现在您可以添加拦截器:

 

Java代码 复制代码 收藏代码
  1. import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;   
  2. import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;   
  3. ...   
  4.   
  5. Map<String,Object> inProps= new HashMap<String,Object>();   
  6. ... // how to configure the properties is outlined below;   
  7.   
  8. WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps);   
  9. cxfEndpoint.getInInterceptors().add(wssIn);   
  10.   
  11. Map<String,Object> outProps = new HashMap<String,Object>();   
  12. ... // how to configure the properties is outlined below;   
  13.   
  14. WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);   
  15. cxfEndpoint.getOutInterceptors().add(wssOut);  

 

Spring XML 配置

如果你使用Spring来构建端点(例如,如Tomcat servlet容器中运行的Web服务),您可以轻松地完成您的bean定义,而不是使用上面。

 

Xml代码 复制代码 收藏代码
  1. <import resource="classpath:META-INF/cxf/cxf.xml" />  
  2. <import resource="classpath*:META-INF/cxf/cxf-extension-*.xml" />  
  3.   
  4. <jaxws:endpoint id="myService"  
  5.    implementor="com.acme.MyServiceImpl"  
  6.    address="http://localhost:9001/MyService">  
  7.   
  8.    <bean id="myPasswordCallback"  
  9.       class="com.mycompany.webservice.ServerPasswordCallback"/>  
  10.   
  11.    <jaxws:inInterceptors>  
  12.       <!-- SAAJ Interceptor needs to be explicitly declared only in CXF 2.0.x -->    
  13.       <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>  
  14.       <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
  15.          <constructor-arg>  
  16.             <map>  
  17.                <entry key="action" value="UsernameToken"/>  
  18.                <entry key="passwordType" value="PasswordDigest"/>  
  19.                <entry key="signaturePropFile" value="..."/>  
  20.                <entry key="passwordCallbackRef">  
  21.                   <ref bean="myPasswordCallback"/>  
  22.                </entry>  
  23.                ...   
  24.             </map>  
  25.          </constructor-arg>  
  26.       </bean>  
  27.    </jaxws:inInterceptors>  
  28. </jaxws:endpoint>  

 

参数的构造元素以上(行动,signaturePropFile等)映射到WSS4J的文本字符串的输入键和值WSHandlerConstantsWSConstants 您在下面的章节中看到相应WSHandlerConstants.XXXXX和WSConstants.XXXX的常量类。

 

因此,通过观察WSHandlerConstants,例如,你可以看到以下的WSHandlerConstants.USERNAME_TOKEN值将需要“的UsernameToken”,而不是在做Spring配置。

 

如果你想避免WSHandlerConstants.XXXXX WSConstants.XXXX常数的文字键,你也可以使用Spring UTIL命名空间,在Spring上下文中引用静态常量,如下图所示。

 

Xml代码 复制代码 收藏代码
  1. <beans  
  2.   ...   
  3.   xmlns:util="http://www./schema/util"  
  4.   ...   
  5.   xsi:schemaLocation="   
  6.         ...   
  7.         http://www./schema/util    
  8.         http://www./schema/util/spring-util.xsd">  
  9.   
  10.   ...   
  11.   
  12.   <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
  13.     <constructor-arg>  
  14.       <map>  
  15.         <entry value="UsernameToken">  
  16.           <key>  
  17.             <util:constant    
  18.                 static-field="org.apache.ws.security.handler.WSHandlerConstants.ACTION"/>  
  19.           </key>  
  20.         </entry>  
  21.         ...   
  22.       </map>  
  23.     </constructor-arg>  
  24.   </bean>  
  25.   
  26.   ...    

 

其他配置选项

虽然CXF WSS4J拦截器支持标准配置属性WSHandlerConstants.XXXXX和WSConstants.XXXX,CXF还提供了一些额外的低水平WSS4J和其他一些安全相关的拦截器配置功能的访问。

验证签名和/或加密邮件内容

2.2.8 CXF的,CryptoCoverageChecker拦截允许不迁移到一个基于WS - SecurityPolicy来配置一个验证签名和加密消息内容的覆盖面。 拦截器可以支持两种元素的含量水平的签名和加密覆盖的执法(知道签名和内容的结合,并不代表一个类型的覆盖面和覆盖范围的有效组合)。 要使用API??配置这个拦截器,请按照下面的例子。

 

Java代码 复制代码 收藏代码
  1. import org.apache.cxf.ws.security.wss4j.CryptoCoverageChecker;   
  2. import org.apache.cxf.ws.security.wss4j.CryptoCoverageChecker.XPathExpression;   
  3. import org.apache.cxf.ws.security.wss4j.CryptoCoverageUtil.CoverageScope;   
  4. import org.apache.cxf.ws.security.wss4j.CryptoCoverageUtil.CoverageType;   
  5.   
  6. Map<String, String> prefixes = new HashMap<String, String>();   
  7.         prefixes.put("ser""http://www.");   
  8.         prefixes.put("soap""http://schemas./soap/envelope/");   
  9.   
  10. List<XPathExpression> xpaths = Arrays.asList(   
  11.     new XPathExpression("//ser:Header", CoverageType.SIGNED,    
  12.         CoverageScope.ELEMENT),   
  13.     new XPathExpression("//soap:Body", CoverageType.ENCRYPTED,    
  14.         CoverageScope.CONTENT));   
  15.   
  16. CryptoCoverageChecker checker = new CryptoCoverageChecker(prefixes, xpaths);  

 

 拦截器也可以在使用常规的bean定义格式Spring配置。

上述配置后拦截,只需将您的客户端或服务器的拦截器链与WSS4J拦截previsouly显示拦截。 确保您包括W??SS4JInInterceptor链中的所有请求将被拒绝,如果你执行任何覆盖的XPath。

定制处理器

 

CXF的2.0.10和2.1.4,您可以指定自定义WSS4J处理器配置的WSS4JInInterceptor。 要激活此配置选项,提供一个非WSS4J的产权界定,wss4j.processor.map,WSS4JInInterceptor在 Spring 的例子所示。

 

相同configuratoin可以通过API以及acheieved。 关键值是一个XML的WS - S的头元素的限定名称与给定的处理器实现过程。 条目的值可以是一个字符串,代表一个实例处理器,处理器,或者为null禁用处理给定的WS - S的头元素的对象的类名。

 

Xml代码 复制代码 收藏代码
  1. <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
  2.   <constructor-arg>  
  3.     <map>  
  4.       ...   
  5.       <!-- This reconfigures the processor implementation that WSS4j uses to    
  6.                process a WS-S Signature element. -->  
  7.       <entry key="wss4j.processor.map">  
  8.         <map key-type="javax.xml.namespace.QName">  
  9.           <entry value="my.class">  
  10.             <key>  
  11.               <bean class="javax.xml.namespace.QName">  
  12.                 <constructor-arg value="http://www./2000/09/xmldsig#"/>  
  13.                 <constructor-arg value="Signature"/>  
  14.               </bean>  
  15.             </key>  
  16.           </entry>  
  17.         </map>  
  18.       </entry>  
  19.       ...   
  20.     </map>  
  21.   </constructor-arg>  
  22. </bean>  

 

自定义操作

2.2.6 CXF的,您可以指定自定义WSS4J WSS4JOutInterceptor行动配置。 要激活此配置选项,提供一个非WSS4J的产权界定,wss4j.action.map,WSS4JOutInterceptor在次年春天的例子所示。

 

相同configuratoin可以通过API以及acheieved。 关键值是一个整数,代表WSS4J行动标识符。 条目的值可以是一个字符串,代表的行动,以实例的类名或对象实施行动。 此配置选项可以覆盖内置的行动实现,或添加您自己的。

 

Xml代码 复制代码 收藏代码
  1. <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">  
  2.   <constructor-arg>  
  3.     <map>  
  4.       ...   
  5.       <!-- Redefines the action for SAMLTokenSigned    
  6.                to use a custom implementation.  -->  
  7.       <entry key="wss4j.action.map">  
  8.         <map key-type="java.lang.Integer" value-type="java.lang.Object">  
  9.           <entry key="0x10" value-ref="mySamlTokenSignedAction"/>  
  10.         </map>  
  11.       </entry>      ...   
  12.     </map>  
  13.   </constructor-arg>  
  14. </bean>  

配置WS - Security的动作

 

用户名令牌认证

WS - Security支持指定标记的方法很多。 其中之一是的UsernameToken头。 它是一种标准的方式传达到另一个端点的用户名和密码或密码消化。 一定要检讨绿洲UserNameToken配置文件规范 为重要的安全考虑,在使用UsernameTokens时。 注意规范的建议,为防范重放攻击,nonce的支持尚未得到落实CXF或WSS4J。

对于服务器端,你需要设置以下WSS4JInInterceptor属性(见上面 的代码示例):

 

 
Java代码 复制代码 收藏代码
  1. inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);   
  2. // Password type : plain text   
  3. inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);   
  4. // for hashed password use:   
  5. //properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);   
  6. // Callback used to retrieve password for given user.   
  7. inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,    
  8.     ServerPasswordHandler.class.getName());  

 

密码回调类,允许您检索检索给定用户的密码,这样的WS - Security可以判断,如果他们授权。 这里是一个小例子:

 

Java代码 复制代码 收藏代码
  1. import java.io.IOException;   
  2. import javax.security.auth.callback.Callback;   
  3. import javax.security.auth.callback.CallbackHandler;   
  4. import javax.security.auth.callback.UnsupportedCallbackException;   
  5. import org.apache.ws.security.WSPasswordCallback;   
  6.   
  7. public class ServerPasswordCallback implements CallbackHandler {   
  8.   
  9.     public void handle(Callback[] callbacks) throws IOException,    
  10.         UnsupportedCallbackException {   
  11.   
  12.         WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];   
  13.   
  14.         if (pc.getIdentifier().equals("joe")) {   
  15.             // set the password on the callback. This will be compared to the   
  16.             // password which was sent from the client.   
  17.             pc.setPassword("password");   
  18.         }   
  19.     }   
  20.   
  21. }  

 

请注意,包括CXF的2.3.x,一个纯文本的密码(或任何其他未知的密码类型)特殊情况的密码验证委托回调类 ,看到org.apache.ws.security。 processor.UsernameTokenProcessor#handleUsernameToken()方法的Javadoc WSS4J 项目。 在这种情况下,ServerPasswordCallback应类似以下:

 

Java代码 复制代码 收藏代码
  1. public class ServerPasswordCallback implements CallbackHandler {   
  2.   
  3.     public void handle(Callback[] callbacks) throws IOException,    
  4.         UnsupportedCallbackException {   
  5.   
  6.         WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];   
  7.   
  8.         if (pc.getIdentifer().equals("joe") {   
  9.            if (!pc.getPassword().equals("password")) {   
  10.                 throw new IOException("wrong password");   
  11.            }   
  12.         }   
  13.     }   
  14.   
  15. }  

 

CXF的2.4起,回调处理程序提供的所有情况下的密码,并验证是在内部完成(但可配置)。 更多信息, 参见这里。
在客户端,您将要配置的WSS4J传出属性:

 

Java代码 复制代码 收藏代码
  1. outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);   
  2. // Specify our username   
  3. outProps.put(WSHandlerConstants.USER, "joe");   
  4. // Password type : plain text   
  5. outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);   
  6. // for hashed password use:   
  7. //properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);   
  8. // Callback used to retrieve password for given user.   
  9. outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,    
  10.     ClientPasswordHandler.class.getName());  

 

再次,我们正在使用的密码回调,除了这个时间,而不是说明我们在服务器端的密码,我们指定的密码,我们要随消息一起发送。 这是我们没有我们的配置文件存储在我们的密码。

 

Java代码 复制代码 收藏代码
  1. import java.io.IOException;   
  2. import javax.security.auth.callback.Callback;   
  3. import javax.security.auth.callback.CallbackHandler;   
  4. import javax.security.auth.callback.UnsupportedCallbackException;   
  5. import org.apache.ws.security.WSPasswordCallback;   
  6.   
  7. public class ClientPasswordCallback implements CallbackHandler {   
  8.   
  9.     public void handle(Callback[] callbacks) throws IOException,    
  10.         UnsupportedCallbackException {   
  11.   
  12.         WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];   
  13.   
  14.         // set the password for our message.   
  15.         pc.setPassword("password");   
  16.     }   
  17.   
  18. }  

 

在多个用户使用不同的密码的情况下, 使用 WSPasswordCallback“getIdentifier()方法来获得当前的SOAP请求的用户名。

 

这里是一个例子 使用拦截器(使用UsernameToken的)的注释实施的WS - Security 。

 

使用X.509证书

X.509证书令牌简介( PDF )提供了另一种实现WS - Security的选项。 对于签名和加密操作,你需要创建一个公共和私人的关键,所涉及的实体。 您可以通过以下步骤为您的开发环境生成自签名的密钥对。 记住这些不会象Verisign的外部权威签署的,所以在生产中使用不恰当的。

 

1。 创建与给定的别名,像“myAlias??”/“myAlias??Password”在密钥库密码私钥(由密码保护 安全原因)

Java代码 复制代码 收藏代码
  1. keytool -genkey -alias myAlias -keypass myAliasPassword -keystore \    
  2.   privatestore.jks -storepass keyStorePassword -dname "cn=myAlias" -keyalg RSA  
 

别名,是一个简单的的方法来确定密钥对。 在这种情况下,我们使用的是RSA算法。

 

2。 自签署的证书(在生产环境中,这将是做一个像VeriSign这样的公司)。

 

Java代码 复制代码 收藏代码
  1. keytool -selfcert -alias myAlias -keystore privatestore.jks \    
  2.     -storepass keyStorePassword -keypass myAliasPassword  

 

 3。 从我们的私人密钥库中导出的公钥文件命名key.rsa

 

Java代码 复制代码 收藏代码
  1. keytool -export -alias myAlias -file key.rsa -keystore privatestore.jks \    
  2.     -storepass keyStorePassword  

 

4。 公钥导入到新的keystore:

 

keytool -import


 -alias myAlias  -file key.rsa -keystore publicstore.jks \ 
    -storepass keyStorePassword

 

所以,现在我们有两个密钥库包含我们的钥匙 - 公共(publicstore.jks)和私人(privatestore.jks)。 他们都有keystore密码keyStorePass(不建议用于生产,但发展确定)和别名设置到myAlias??。

 

该文件key.rsa可以从文件系统中删除,因为它只是暂时的使用。 强烈建议,因为一个keystore受密码保护密钥库中存储键。

 

密钥生成一个更详细的说明可以在这里找到:
http://translate./translate_c?rurl=translate.google.com&tl=zh-CN&u=http://java.sun.com/javase/6/docs/technotes/tools/solaris/keytool.html&usg=ALkJrhhLjYALP1Uy6Fxgp3Eir6ri7m6OsQ

如何创建一个生产证书,可以在这里找到:
http://translate./translate_c?rurl=translate.google.com&tl=zh-CN&u=http://support.globalsign.net/en/objectsign/java.cfm&usg=ALkJrhiU-dm7vFoukrSuKbmR-u0MK-onRA

 

签名

 

邮件签名是用来验证该消息只能从某个发件人的收件人,以及消息在传输过程中不改变。 特别的发件人加密一个用其私有密钥的消息消化(散列),并在收件人unencrypting用发件人的公钥的哈希,并重新计算,以确保消息是不是在传输过程中改变的消息摘要(即,消化计算值由发送者和接收者都是一样的)。 对于这一过程的发生,你必须确保客户端的公钥已经被导入到服务器的keystore使用keytool。

 

在客户端,我们传出的WS - Security属性看起来像这样(见上面 的代码示例):

 

Java代码 复制代码 收藏代码
  1. outProps.put(WSHandlerConstants.ACTION, "Signature");   
  2. outProps.put(WSHandlerConstants.USER, "myAlias");   
  3. outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,    
  4.     ClientCallbackHandler.class.getName());   
  5. outProps.put(WSHandlerConstants.SIG_PROP_FILE, "client_sign.properties");  

 指定的用户客户端的密钥别名。 密码回调类是负责提供该密钥的密码。

 

提示

为X.509的支持,您将通常有多个动作,例如加密与签名。 对于这些情况,只是空间独立的行动,在ACTION属性如下:

Java代码 复制代码 收藏代码
  1. outProps.put(WSHandlerConstants.ACTION    
  2.      WSHandlerConstants.TIMESTAMP +“”+    
  3.      WSHandlerConstants.SIGNATURE +“”+    
  4.      WSHandlerConstants.ENCRYPT);  
 

或者,您可能空间单独的字符串文字,您会看到在上面的Spring配置(例如,“签名加密”)

 

我们client_sign.properties文件包含几个设置来配置WSS4J:

 

Java代码 复制代码 收藏代码
  1. org.apache.ws.security.crypto.provider = org.apache.ws.security.components.crypto.Merlin   
  2.   
  3. org.apache.ws.security.crypto.merlin.keystore.type = JKS   
  4.   
  5. org.apache.ws.security.crypto.merlin.keystore.password = keyStorePassword  
 

 

在服务器端,我们需要来配置我们的传入WSS4J拦截,使用客户端的公钥来验证签名。

 

Java代码 复制代码 收藏代码
  1. inProps.put(WSHandlerConstants.ACTION,“签字”);   
  2.   
  3. nbsp;inProps.put(WSHandlerConstants.SIG_PROP_FILE,“server.properties”);  
 

我们server_sign.properties文件包含几个设置来配置WSS4J:

 

Java代码 复制代码 收藏代码
  1. org.apache.ws.security.crypto.provider = org.apache.ws.security.components.crypto.Merlin   
  2.   
  3. org.apache.ws.security.crypto.merlin.keystore.type = JKS   
  4.   
  5. org.apache.ws.security.crypto.merlin.keystore.password = amex123   
  6.   
  7. org.apache.ws.security.crypto.merlin.file = server_keystore.jks  

加密

加密涉及的发件人与收件人的公钥加密的消息,以确保,只有收件人可以读取消息(只有收件人有其自己的私人密钥,解密消息所必需的。)这要求发件人以有收件人的公钥在其密钥库。

 

 

用于加密的过程是非常相似,的确通常与上面的签名过程中结合。 我们的WS - Security的测试 样品提供了一个加密的请求和响应的例子, 还要检查这个 博客条目月底到年底更显示SOAP请求和响应的签名和加密的例子。

 

 

以下是本人参照的几个网址:

 

http://www./dev-blog/apache-cxf-tutorial-ws-security-with-spring/

http://cxf./docs/ws-security.html

http://blog.csdn.net/kunshan_shenbin/article/details/3813000


http://xiaofengtoo./admin/blogs/1130802/  


http://xiaofengtoo./admin/blogs/1130802/

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约