Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从Soap信封获取X509证书别名_Java_Spring Boot_Soap_X509certificate_Ws Security - Fatal编程技术网

Java 从Soap信封获取X509证书别名

Java 从Soap信封获取X509证书别名,java,spring-boot,soap,x509certificate,ws-security,Java,Spring Boot,Soap,X509certificate,Ws Security,我有一个用SpringBoot开发的JavaWebService,使用SOAP1.2和ws-security以及X509证书。我希望能够读取客户端正在使用的私钥的别名。 我原以为我可以从SOAP信封中得到这些信息,但我为此苦苦挣扎了几个小时,却一无所获。有可能吗 问题是服务器上使用的密钥库jks(包含所有客户端公钥的列表)需要能够区分不同的客户端,以便正确加密响应 任何提示?将xml字符串转换为org.w3c.dom.Document,您可以通过标记名获取证书节点。只需将标记名替换为您应该使用的

我有一个用SpringBoot开发的JavaWebService,使用SOAP1.2和ws-security以及X509证书。我希望能够读取客户端正在使用的私钥的别名。 我原以为我可以从SOAP信封中得到这些信息,但我为此苦苦挣扎了几个小时,却一无所获。有可能吗

问题是服务器上使用的密钥库jks(包含所有客户端公钥的列表)需要能够区分不同的客户端,以便正确加密响应


任何提示?

将xml字符串转换为org.w3c.dom.Document,您可以通过标记名获取证书节点。只需将标记名替换为您应该使用的名称

Node certNode = doc.getElementsByTagName("ds:X509Certificate").item(0);
String x509Cert = certNode.getTextContent();
好的,我终于明白了

我必须开发一个spring boot SmartEndPointInterceptor。像这样:

public class TrustSenderInterceptor extends Wss4jSecurityInterceptor implements SmartEndpointInterceptor {

Crypto                    crypto  = null;
public static final QName KEYINFO = new QName( "http://www.w3.org/2000/09/xmldsig#", "KeyInfo" );

@Override
public boolean shouldIntercept( MessageContext messageContext, Object endpoint ) {

    WebServiceMessage wsMessage = messageContext.getRequest();
    SoapMessage soapMessage = (SoapMessage) wsMessage;      

    Document doc = soapMessage.getDocument();
    RequestData requestData = initializeRequestData( messageContext );
    //get the soap Header element
    Element soapHeaderElement = WSSecurityUtil.getSOAPHeader( doc );
    Element wssSecurityElement = null;
    X509Certificate cert = null;
    try {
        //read the part of the soap Header starting with <wsse:Security>
        wssSecurityElement = WSSecurityUtil.getSecurityHeader( soapHeaderElement, null, true );
        //read the certificate
        cert = getCertificateFromKeyInfo( requestData, wssSecurityElement );
    } catch ( WSSecurityException e ) {
        e.printStackTrace();
        logger.error( "TrustSenderInterceptor - Can't read the Certificate INFO" );
    }

    //get the certificate's subjectDN component
    Principal subjectDN = cert.getSubjectDN();
    //read the CN
    String alias = extractCN( subjectDN.toString() );
    //finally, i set the alias just found in the certificate. In this way i can always pick the correct key in the keystore and handle multiple clients with different keypairs ;-)
    setSecurementEncryptionUser( alias );

    return true;
}

private X509Certificate getCertificateFromKeyInfo( RequestData data, Element securityHeader ) throws WSSecurityException {

    X509Certificate[] certs;

    EncryptedKeySTRParser decryptedBytes;
    //navigate <wsse:Security> and search for ds:KeyInfo
    Element secTokenRef = getSecTokenRef( securityHeader );
    //Initialize WSS4J parser
    STRParserParameters encryptedEphemeralKey1 = new STRParserParameters();
    data.setWsDocInfo( new WSDocInfo( securityHeader.getOwnerDocument() ) );
    //Set the crypto object. It is necessary.        
    data.setDecCrypto( crypto );
    encryptedEphemeralKey1.setData( data );
    encryptedEphemeralKey1.setStrElement( secTokenRef );
    decryptedBytes = new EncryptedKeySTRParser();
    //parse the key
    STRParserResult refList = decryptedBytes.parseSecurityTokenReference( encryptedEphemeralKey1 );
    certs = refList.getCertificates();

    if ( certs == null || certs.length < 1 ) {
        logger.error( "TrustSenderInterceptor - Couldn't find any certificate" );
        return null;
    }
    return certs[0];
}

private static Element getSecTokenRef( Element soapSecurityHeader ) throws WSSecurityException {

    for ( Node currentChild = soapSecurityHeader.getFirstChild(); currentChild != null; currentChild = currentChild.getNextSibling() ) {
        if ( WSConstants.SIGNATURE.getLocalPart().equals( currentChild.getLocalName() ) && WSConstants.SIGNATURE.getNamespaceURI().equals( currentChild.getNamespaceURI() ) ) {
            Element signatureEl = (Element) currentChild;
            for ( Node innerCurrentChild = signatureEl.getFirstChild(); innerCurrentChild != null; innerCurrentChild = innerCurrentChild.getNextSibling() ) {
                if ( KEYINFO.getLocalPart().equals( innerCurrentChild.getLocalName() ) && KEYINFO.getNamespaceURI().equals( innerCurrentChild.getNamespaceURI() ) ) {
                    return (Element) innerCurrentChild.getFirstChild();
                }
            }
        }
    }
    return null;
}

private String extractCN( String subjectCN ) {
    String ret = null;
    String[] parts = subjectCN.split( "," );
    ret = parts[0].split( "=" )[1];
    return ret;
}

public void setSignatureCrypto( Crypto c ) {
    this.crypto = c;
}
公共类TrustSenderInterceptor扩展Wss4jSecurityInterceptor实现SmartEndpointInterceptor{
Crypto-Crypto=null;
公共静态最终QName KEYINFO=新QName(“http://www.w3.org/2000/09/xmldsig#“,“KeyInfo”);
@凌驾
公共布尔值shouldIntercept(MessageContext MessageContext,对象端点){
WebServiceMessage wsMessage=messageContext.getRequest();
SoapMessage SoapMessage=(SoapMessage)wsMessage;
Document doc=soapMessage.getDocument();
RequestData RequestData=initializeRequestData(messageContext);
//获取soap头元素
元素soapHeaderElement=WSSecurityUtil.getSOAPHeader(doc);
元素wssSecurityElement=null;
X509证书证书证书=空;
试一试{
//阅读soap标题中以开头的部分
wssSecurityElement=WSSecurityUtil.getSecurityHeader(soapHeaderElement,null,true);
//阅读证书
cert=getCertificateFromKeyInfo(requestData,wssSecurityElement);
}捕获(WSSecurityException e){
e、 printStackTrace();
logger.error(“TrustSenderInterceptor-无法读取证书信息”);
}
//获取证书的subjectDN组件
主体主体DN=证书getSubjectDN();
//阅读CN
字符串别名=extractCN(subjectDN.toString());
//最后,我设置了刚刚在证书中找到的别名。这样,我可以始终在密钥库中选择正确的密钥,并使用不同的密钥对处理多个客户端;-)
设置安全加密用户(别名);
返回true;
}
私有X509证书getCertificateFromKeyInfo(RequestData数据,元素securityHeader)引发WSSecurityException{
X509证书[]证书;
EncryptedKeySTRParser decryptedBytes;
//导航并搜索ds:KeyInfo
元素secTokenRef=getSecTokenRef(securityHeader);
//初始化WSS4J解析器
STRParserParameters encryptedEphemeralKey1=新的STRParserParameters();
setWsDocInfo(新的WSDocInfo(securityHeader.getOwnerDocument());
//设置加密对象。这是必需的。
数据。setDecCrypto(加密);
encryptedEphemeralKey1.setData(数据);
encryptedEphemeralKey1.setStrElement(secTokenRef);
decryptedBytes=新的EncryptedKeySTRParser();
//解析密钥
STRParserResult refList=decryptedBytes.parseSecurityTokenReference(encryptedEphemeralKey1);
certs=refList.getCertificates();
if(certs==null | | certs.length<1){
错误(“TrustSenderInterceptor-找不到任何证书”);
返回null;
}
返回证书[0];
}
私有静态元素getSecTokenRef(元素soapSecurityHeader)引发WSSecurityException{
对于(节点currentChild=soapSecurityHeader.getFirstChild();currentChild!=null;currentChild=currentChild.getNextSibling()){
if(WSConstants.SIGNATURE.getLocalPart().equals(currentChild.getLocalName())&&WSConstants.SIGNATURE.getNamespaceURI().equals(currentChild.getNamespaceURI())){
元素SignatureEel=(元素)currentChild;
对于(节点innerCurrentChild=SignatureEEL.getFirstChild();innerCurrentChild!=null;innerCurrentChild=innerCurrentChild.getNextSibling()){
if(KEYINFO.getLocalPart().equals(innerCurrentChild.getLocalName())和&KEYINFO.getNamespaceURI().equals(innerCurrentChild.getNamespaceURI())){
返回(元素)innerCurrentChild.getFirstChild();
}
}
}
}
返回null;
}
私有字符串提取CN(字符串主题CN){
字符串ret=null;
String[]parts=subjectCN.split(“,”);
ret=零件[0]。拆分(“=”[1];
返回ret;
}
公共无效设置签名加密(加密c){
this.crypto=c;
}
我希望它能帮助别人!感谢你的巨大鼓舞