【问题标题】:Get the X509 certificate alias from a Soap Envelope从 Soap Envelope 获取 X509 证书别名
【发布时间】:2020-11-16 18:24:36
【问题描述】:

我有一个使用 spring-boot 开发的 java webservice,使用 SOAP 1.2 和带有 X509 证书的 ws-security。我希望能够读取客户端使用的私钥的别名。 我以为我可以从 SOAP 信封中获取这些信息,但我已经为此苦苦挣扎了几个小时,但无济于事。有没有可能?

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

有什么提示吗?

【问题讨论】:

    标签: java spring-boot soap x509certificate ws-security


    【解决方案1】:

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

    Node certNode = doc.getElementsByTagName("ds:X509Certificate").item(0);
    String x509Cert = certNode.getTextContent();
    

    【讨论】:

      【解决方案2】:

      好的,我终于明白了。

      我必须开发一个 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;
      }
      

      我希望它可以帮助那里的人!感谢this 的巨大启发。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-24
        • 1970-01-01
        • 1970-01-01
        • 2016-01-14
        • 2021-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多