1

webservice复杂加密签名(2)java调用

 2 years ago
source link: https://wakzz.cn/2020/04/20/java/webservice%E5%A4%8D%E6%9D%82%E5%8A%A0%E5%AF%86%E7%AD%BE%E5%90%8D(2)java%E8%B0%83%E7%94%A8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>

WSDL转java

image

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.13.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generateDirectory>${basedir}/src/main/java</generateDirectory>
<schemas>
<schema>
<fileset>
<directory>${basedir}/src/main/resources/wsdl</directory>
<includes>
<include>*.wsdl</include>
<include>*.wsd</include>
</includes>
</fileset>
</schema>
</schemas>
</configuration>
</plugin>
</plugins>
</build>
mvn org.jvnet.jaxb2.maven2:maven-jaxb2-plugin:0.13.2:generate

image

HTTPS签名

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.ClientHttpRequestMessageSender;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;

@Slf4j
@Configuration
public class SoapConfig {

@Value("${mastercard.keystore.client.path}")
private String clientKeystorePath;
@Value("${mastercard.keystore.client.password}")
private String clientPassword;

@Bean
public WebServiceMessageSender webServiceMessageSender() throws Exception {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
byte[] keystoreBytes;
try (InputStream inputStream = resolver.getResource(clientKeystorePath).getInputStream()) {
keystoreBytes = IOUtils.toByteArray(inputStream);
} catch (Exception e) {
log.error("https秘钥文件client.jks读取异常, keystore: {}", clientKeystorePath);
throw e;
}

KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new ByteArrayInputStream(keystoreBytes), clientPassword.toCharArray());

SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keystore, clientPassword.toCharArray())
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
requestFactory.setConnectTimeout(10_000);
requestFactory.setReadTimeout(10_000);
ClientHttpRequestMessageSender messageSender = new ClientHttpRequestMessageSender();
messageSender.setRequestFactory(requestFactory);
return messageSender;
}

}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;

import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.soap.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;

@Slf4j
@Component
public class SoapSignService {

private final KeyStore keystore;
private final String password;
private final String keystoreAlias;

@Value("${mastercard.system.institutionName}")
private String institutionName;

@Autowired
public SoapSignService(@Value("${mastercard.keystore.sign.path}") String path,
@Value("${mastercard.keystore.sign.password}") String password,
@Value("${mastercard.keystore.sign.alias}") String keystoreAlias) throws Exception {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
byte[] keystoreBytes;
try (InputStream inputStream = resolver.getResource(path).getInputStream()) {
keystoreBytes = IOUtils.toByteArray(inputStream);
} catch (Exception e) {
log.error("签名秘钥文件signing.jks读取异常, keystore: {}", path);
throw e;
}

this.keystore = KeyStore.getInstance("PKCS12");
this.keystore.load(new ByteArrayInputStream(keystoreBytes), password.toCharArray());
this.password = password;
this.keystoreAlias = keystoreAlias;
}

private PrivateKey getKeyFormCert() throws Exception {
return (PrivateKey) keystore.getKey(keystoreAlias, password.toCharArray());
}

private java.security.cert.Certificate getCertificate() throws Exception {
return keystore.getCertificate(keystoreAlias);
}

public void sign(WebServiceMessage message) {
sign("", message);
}

public void sign(String appId, WebServiceMessage message) {
this.sign(appId, ((SaajSoapMessage) message).getSaajMessage());
}

public void sign(String appId, SOAPMessage soapMessage) {
try {
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
soapEnvelope.setPrefix("soapenv");
soapEnvelope.removeNamespaceDeclaration("SOAP-ENV");
soapEnvelope.addNamespaceDeclaration("com", "http://common.ws.mcrewards.mastercard.com/");

SOAPHeader header = soapMessage.getSOAPHeader();
header.setPrefix("soapenv");
SOAPElement identity = header.addChildElement("identity", "com");
identity.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "IDENTITY");

SOAPElement appID = identity.addChildElement("appID");
appID.addTextNode(appId);
SOAPElement institutionName = identity.addChildElement("institutionName");
institutionName.addTextNode(this.institutionName);

SOAPBody soapBody = soapMessage.getSOAPBody();
soapBody.setPrefix("soapenv");
soapBody.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "Body");

signSOAPMessage(soapMessage);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}

private void signSOAPMessage(SOAPMessage soapMessage) throws Exception {
// Create the security element
SOAPElement soapHeader = soapMessage.getSOAPHeader();
SOAPElement securityElement = soapHeader.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
securityElement.addNamespaceDeclaration("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

// (i) Extract the certificate from the .p12 file.
java.security.cert.Certificate cert = getCertificate();

// (ii) Add Binary Security Token. The base64 encoded value of the ROS digital certificate.
SOAPElement binarySecurityToken = addBinarySecurityToken(securityElement, soapMessage, cert);

//(iii) Add Timestamp element
SOAPElement timestamp = addTimestamp(securityElement, soapMessage);

// (iv) Add signature element
// Get private key from ROS digital certificate
PrivateKey key = getKeyFormCert();
SOAPElement securityTokenReference = addSecurityToken(securityElement);
addSignature(securityElement, key, securityTokenReference, soapMessage.getSOAPBody(), timestamp, binarySecurityToken);
}

private SOAPElement addSecurityToken(SOAPElement signature) throws SOAPException {
SOAPElement securityTokenReference = signature.addChildElement("SecurityTokenReference", "wsse");
SOAPElement reference = securityTokenReference.addChildElement("Reference", "wsse");
reference.setAttribute("URI", "#X509Token");
return securityTokenReference;
}

private void addSignature(SOAPElement signatureElement, PrivateKey privateKey, SOAPElement securityTokenReference, SOAPBody soapBody, SOAPElement timestamp, SOAPElement binarySecurityToken) throws Exception {
String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());

//Digest method
javax.xml.crypto.dsig.DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod("http://www.w3.org/2001/04/xmlenc#sha512", null);
ArrayList<Transform> transformList = new ArrayList<>();

//Transform
Transform envTransform = xmlSignatureFactory.newTransform("http://www.w3.org/2001/10/xml-exc-c14n#", (TransformParameterSpec) null);
transformList.add(envTransform);

//References
ArrayList<Reference> referenceList = new ArrayList<>();
Reference x509 = xmlSignatureFactory.newReference("#X509Token", digestMethod, transformList, null, null);
Reference refTS = xmlSignatureFactory.newReference("#TS", digestMethod, transformList, null, null);
Reference refBody = xmlSignatureFactory.newReference("#Body", digestMethod, transformList, null, null);
Reference header = xmlSignatureFactory.newReference("#IDENTITY", digestMethod, transformList, null, null);
referenceList.add(x509);
referenceList.add(refTS);
referenceList.add(refBody);
referenceList.add(header);

javax.xml.crypto.dsig.CanonicalizationMethod cm = xmlSignatureFactory.newCanonicalizationMethod("http://www.w3.org/2001/10/xml-exc-c14n#", (C14NMethodParameterSpec) null);
javax.xml.crypto.dsig.SignatureMethod sm = xmlSignatureFactory.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", null);
SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(cm, sm, referenceList);


DOMSignContext signContext = new DOMSignContext(privateKey, signatureElement);
signContext.setDefaultNamespacePrefix("ds");
signContext.putNamespacePrefix("http://www.w3.org/2000/09/xmldsig#", "ds");

//These are required for new Java versions
signContext.setIdAttributeNS(soapBody, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
signContext.setIdAttributeNS(timestamp, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
signContext.setIdAttributeNS(binarySecurityToken, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");

KeyInfoFactory keyFactory = KeyInfoFactory.getInstance();
DOMStructure domKeyInfo = new DOMStructure(securityTokenReference);
javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo));
javax.xml.crypto.dsig.XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
signContext.setBaseURI("");
signature.sign(signContext);
}

private SOAPElement addTimestamp(SOAPElement securityElement, SOAPMessage soapMessage) throws SOAPException {
SOAPElement timestamp = securityElement.addChildElement("Timestamp", "wsu");
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
timestamp.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "TS");

String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssX";
DateTimeFormatter timeStampFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
ZonedDateTime zonedDateTime = ZonedDateTime.now();
timestamp.addChildElement("Created", "wsu").setValue(timeStampFormatter.format(zonedDateTime.toInstant().atZone(ZoneId.of("UTC"))));
timestamp.addChildElement("Expires", "wsu").setValue(timeStampFormatter.format(zonedDateTime.plusSeconds(60).toInstant().atZone(ZoneId.of("UTC"))));
return timestamp;
}

private SOAPElement addBinarySecurityToken(SOAPElement securityElement, SOAPMessage soapMessage, java.security.cert.Certificate cert) throws Exception {
byte[] certByte = cert.getEncoded();
SOAPElement binarySecurityToken = securityElement.addChildElement("BinarySecurityToken", "wsse");

binarySecurityToken.setAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
binarySecurityToken.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();

binarySecurityToken.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "X509Token");
binarySecurityToken.addTextNode(Base64.getEncoder().encodeToString(certByte));
return binarySecurityToken;
}

}
import com.mastercard.mcrewards.ws.common.EmptyElement;
import com.mastercard.mcrewards.ws.diagnostic.ApplicationStatus;
import com.mastercard.mcrewards.ws.diagnostic.CurrentVersion;
import com.mastercard.mcrewards.ws.diagnostic.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.transport.WebServiceMessageSender;

import javax.xml.bind.JAXBElement;

@Service
public class SoapDiagnosticService extends WebServiceGatewaySupport {

private static final ObjectFactory factory = new com.mastercard.mcrewards.ws.diagnostic.ObjectFactory();
private static final String packagePath = "com.mastercard.mcrewards.ws.diagnostic";

private SoapSignService soapSignService;

@Autowired
public SoapDiagnosticService(WebServiceMessageSender messageSender,
SoapSignService soapSignService,
@Value("${mastercard.service.diagnosticServiceLink}") String link) {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(packagePath);
this.setDefaultUri(link);
this.setMarshaller(marshaller);
this.setUnmarshaller(marshaller);
this.setMessageSender(messageSender);
this.soapSignService = soapSignService;
}

public String doEcho(String request) {
JAXBElement<String> source = factory.createDoEcho(request);
WebServiceMessageCallback wsCallback = message -> soapSignService.sign(message);
JAXBElement response = (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(source, wsCallback);
return (String) response.getValue();
}

}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK