我有一个使用 spring-boot 开发的 java webservice,使用 SOAP 1.2 和带有 X509 证书的 ws-security。我希望能够读取客户端使用的私钥的别名。我以为我可以从 SOAP 信封中获取这些信息,但我已经为此苦苦挣扎了几个小时,但无济于事。甚至可能吗?
问题是服务器上使用的密钥库 jks(包含所有客户端公钥的列表)需要能够区分不同的客户端,以便正确加密响应。
有什么提示吗?
我有一个使用 spring-boot 开发的 java webservice,使用 SOAP 1.2 和带有 X509 证书的 ws-security。我希望能够读取客户端使用的私钥的别名。我以为我可以从 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;
}
我希望它可以帮助那里的人!感谢这个巨大的灵感。