我有一个用springboot开发的javawebservice,使用soap1.2和ws-security以及x509证书。我希望能够读取客户端正在使用的私钥的别名。我以为我可以从soap信封里得到这些信息,但我已经为此奋斗了几个小时,但毫无结果。有可能吗?问题是,服务器上使用的密钥库jks(包含所有客户机公钥的列表)需要能够区分不同的客户机,以便正确加密响应。有什么提示吗?
eulz3vhy1#
好吧,我终于明白了。我不得不开发一个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; }
我希望它能帮助别人!感谢这个巨大的灵感。
9q78igpj2#
将xml字符串转换为org.w3c.dom.document,就可以通过标记名获得证书节点。只需将标记名替换为您应该使用的名称。
Node certNode = doc.getElementsByTagName("ds:X509Certificate").item(0); String x509Cert = certNode.getTextContent();
2条答案
按热度按时间eulz3vhy1#
好吧,我终于明白了。
我不得不开发一个spring-boot-smartendpointinterceptor。这样地:
我希望它能帮助别人!感谢这个巨大的灵感。
9q78igpj2#
将xml字符串转换为org.w3c.dom.document,就可以通过标记名获得证书节点。只需将标记名替换为您应该使用的名称。