如何使用 CXF 获取发件人 Public 密钥?
How do I get the senders Public Key using CXF?
我想弄清楚是否可以获取调用方法的发送方的 Public 密钥作为方法参数。
如果我有一个 CXF 发布的具有非对称安全性的 SOAP 服务,是否可以通过某种方式告诉 CXF 使调用程序的 public 密钥可用于它在调用 Web 服务时调用的方法?
我希望能够将 public 键定义为方法调用的额外参数,例如:
public interface Webservices{
public ReturnVal soapMethod(SomeObject input, SomeOtherObject moreInput, PublicKey invokerPubKey)
}
返回的公钥不必作为 PublicKey 对象返回,字节数组或我可以使用的任何其他格式都可以。
我也不太清楚这是否可以通过回调或拦截器来完成,但考虑到可以有多个处理线程,我不知道如何做。再次,将不胜感激。
我不一定需要密钥对象本身,获取别名或任何其他唯一标识符也可以,只要它能引导我找到存储的密钥。
SSL 协议本身应该足以做到这一点。如果您使用 HTTPS 发布 Web 服务,那么您可以将服务器配置为向客户端询问它的证书(其中将包含它的 public 密钥)。
为此,您可以检查以下 CXF configuration file 。如您所见,有一部分内容为:
<sec:clientAuthentication want="true" required="true"/>
这告诉服务器在客户端尝试建立连接时它应该请求客户端的证书。
之后,您需要进行更多配置:
服务器应识别签署客户端证书的证书颁发机构。您可以在 server's trust store.
中添加 CA
客户端显然应该有它的证书。如果是 java 应用程序,您可以通过 adding the certificate in a keystore.
来完成
您还可以查看 complete CXF example。
现在您已准备好获取 public 密钥!为此,我将假设您在 Java EE JAX-WS 应用程序中使用 CXF。
第一步是通过添加以下字段将 WebServiceContext 注入您的@WebService:
@Resource
private WebServiceContext webServiceContext;
那么您应该从 WebServiceContext 中获取 HttpServletRequest:
MessageContext messageContext = webServiceContext.getMessageContext();
HttpServletRequest request = (HttpServletRequest)
messageContext.get(MessageContext.SERVLET_REQUEST);
之后,您应该从请求中获取证书链:
X509Certificate[] certificates = (X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate");
最后,您应该从中提取 public 密钥:
PublicKey publicKey = certificates[0].getPublicKey();
(客户端的证书应该是数组中的第一个)
WS-安全
如果您使用的是 WS-Security,您可以执行以下操作:
- 注册拦截器:
<jaxws:inInterceptors>
<bean class="my.beloved.MyWSInterceptor"/>
</jaxws:inInterceptors>
-
将 MyWSInterceptor 拦截器编码为 AbstractSoapInterceptor 的子 class 并实现 handleMessage(SoapMessage message)方法:
public class MyWSInterceptor 扩展了 AbstractSoapInterceptor {
public void handleMessage(SoapMessage message) throws Fault {
List<WSHandlerResult> results = CastUtils.cast((List<?>) message
.get(WSHandlerConstants.RECV_RESULTS));
for (WSHandlerResult wshr : results) {
for (WSSecurityEngineResult wsser : wshr.getResults()) {
PublicKey publicKey = wsser
.get(WSSecurityEngineResult.TAG_PUBLIC_KEY);
}
}
}
}
有关 CXF 中 WS-Security 配置的更多信息,请查看 here。
考虑到您已经为您的网络服务正确配置了两种方式的 SSL,
您可以使用拦截器实现此目的。但是 public 键不会传递给方法调用。
public class TestInterceptor extends AbstractPhaseInterceptor<Message> {
public TestInterceptor() {
super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
TLSSessionInfo tlsSessionInfo = (TLSSessionInfo) message
.get(TLSSessionInfo.class);
if (tlsSessionInfo != null) {
Certificate[] peerCerts = tlsSessionInfo.getPeerCertificates();
for (int i = 0; i < peerCerts.length; i++) {
X509Certificate x509certificate = (X509Certificate)peerCerts[i];
x509certificate.getPublicKey(); //DO SOMETHING WITH PUBLIC KEY
}
} else {
System.out.println(" NO x509certificate ");
}
}
}
通过这种方式,您可以使用 CXF 获取发件人 public 密钥。
然后在您的 cxf-servlet.xml 或其他端点映射中配置上述拦截器,如下所示。
<jaxws:endpoint publish="true" id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld" >
<jaxws:inInterceptors> <ref bean="srinathSSLInterceptor"/></jaxws:inInterceptors>
</jaxws:endpoint>
<bean id="srinathSSLInterceptor" class="TestInterceptor"/>
我想弄清楚是否可以获取调用方法的发送方的 Public 密钥作为方法参数。 如果我有一个 CXF 发布的具有非对称安全性的 SOAP 服务,是否可以通过某种方式告诉 CXF 使调用程序的 public 密钥可用于它在调用 Web 服务时调用的方法?
我希望能够将 public 键定义为方法调用的额外参数,例如:
public interface Webservices{
public ReturnVal soapMethod(SomeObject input, SomeOtherObject moreInput, PublicKey invokerPubKey)
}
返回的公钥不必作为 PublicKey 对象返回,字节数组或我可以使用的任何其他格式都可以。
我也不太清楚这是否可以通过回调或拦截器来完成,但考虑到可以有多个处理线程,我不知道如何做。再次,将不胜感激。
我不一定需要密钥对象本身,获取别名或任何其他唯一标识符也可以,只要它能引导我找到存储的密钥。
SSL 协议本身应该足以做到这一点。如果您使用 HTTPS 发布 Web 服务,那么您可以将服务器配置为向客户端询问它的证书(其中将包含它的 public 密钥)。 为此,您可以检查以下 CXF configuration file 。如您所见,有一部分内容为:
<sec:clientAuthentication want="true" required="true"/>
这告诉服务器在客户端尝试建立连接时它应该请求客户端的证书。
之后,您需要进行更多配置:
服务器应识别签署客户端证书的证书颁发机构。您可以在 server's trust store.
中添加 CA
客户端显然应该有它的证书。如果是 java 应用程序,您可以通过 adding the certificate in a keystore.
来完成
您还可以查看 complete CXF example。
现在您已准备好获取 public 密钥!为此,我将假设您在 Java EE JAX-WS 应用程序中使用 CXF。
第一步是通过添加以下字段将 WebServiceContext 注入您的@WebService:
@Resource
private WebServiceContext webServiceContext;
那么您应该从 WebServiceContext 中获取 HttpServletRequest:
MessageContext messageContext = webServiceContext.getMessageContext();
HttpServletRequest request = (HttpServletRequest)
messageContext.get(MessageContext.SERVLET_REQUEST);
之后,您应该从请求中获取证书链:
X509Certificate[] certificates = (X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate");
最后,您应该从中提取 public 密钥:
PublicKey publicKey = certificates[0].getPublicKey();
(客户端的证书应该是数组中的第一个)
WS-安全
如果您使用的是 WS-Security,您可以执行以下操作:
- 注册拦截器:
<jaxws:inInterceptors>
<bean class="my.beloved.MyWSInterceptor"/>
</jaxws:inInterceptors>
- 将 MyWSInterceptor 拦截器编码为 AbstractSoapInterceptor 的子 class 并实现 handleMessage(SoapMessage message)方法:
public class MyWSInterceptor 扩展了 AbstractSoapInterceptor {
public void handleMessage(SoapMessage message) throws Fault {
List<WSHandlerResult> results = CastUtils.cast((List<?>) message
.get(WSHandlerConstants.RECV_RESULTS));
for (WSHandlerResult wshr : results) {
for (WSSecurityEngineResult wsser : wshr.getResults()) {
PublicKey publicKey = wsser
.get(WSSecurityEngineResult.TAG_PUBLIC_KEY);
}
}
}
}
有关 CXF 中 WS-Security 配置的更多信息,请查看 here。
考虑到您已经为您的网络服务正确配置了两种方式的 SSL, 您可以使用拦截器实现此目的。但是 public 键不会传递给方法调用。
public class TestInterceptor extends AbstractPhaseInterceptor<Message> {
public TestInterceptor() {
super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
TLSSessionInfo tlsSessionInfo = (TLSSessionInfo) message
.get(TLSSessionInfo.class);
if (tlsSessionInfo != null) {
Certificate[] peerCerts = tlsSessionInfo.getPeerCertificates();
for (int i = 0; i < peerCerts.length; i++) {
X509Certificate x509certificate = (X509Certificate)peerCerts[i];
x509certificate.getPublicKey(); //DO SOMETHING WITH PUBLIC KEY
}
} else {
System.out.println(" NO x509certificate ");
}
}
}
通过这种方式,您可以使用 CXF 获取发件人 public 密钥。
然后在您的 cxf-servlet.xml 或其他端点映射中配置上述拦截器,如下所示。
<jaxws:endpoint publish="true" id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld" >
<jaxws:inInterceptors> <ref bean="srinathSSLInterceptor"/></jaxws:inInterceptors>
</jaxws:endpoint>
<bean id="srinathSSLInterceptor" class="TestInterceptor"/>