I have integrated my web site with TFIM for SSO.
SSO is working fine but i am unable to get the Signature in SAMLResponse.
it's getting null. but it is already there in SAMLResponse.
When am trying to get the signature value from samlresponse it giving me nullpointerexception
package com.saml;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Subject;
import org.opensaml.security.SAMLSignatureProfileValidator;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.signature.SignatureValidator;
import org.apache.commons.codec.binary.Base64;
import org.opensaml.xml.validation.ValidationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class ReceiveSAMLResponse {
public String receiveSAMLResponse(HttpServletRequest request)
throws ParserConfigurationException, SAXException, IOException,
UnmarshallingException, ValidationException, CertificateException {
/* Getting the response string from HTTP Request object */
String responseString = (String) request.getParameter("SAMLResponse");
/* Decoding Base64 response string to get the XML string */
String responseXml = new String(Base64.decodeBase64(responseString
.getBytes()));
System.out.println(responseXml);
/* Generating SAML Response object from XML string */
try {
DefaultBootstrap.bootstrap();
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = documentBuilderFactory
.newDocumentBuilder();
ByteArrayInputStream is = new ByteArrayInputStream(
responseXml.getBytes());
Document document = docBuilder.parse(is);
Element element = document.getDocumentElement();
UnmarshallerFactory unmarshallerFactory = Configuration
.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory
.getUnmarshaller(element);
XMLObject xmlObj = unmarshaller.unmarshall(element);
Response response = (Response) xmlObj;
/* Validating the signature on the response */
// validateSignature(response);
/* If validation was successful, get the username from the response. */
Subject subject = response.getAssertions().get(0).getSubject();
String username = subject.getNameID().getValue();
return username;
}
private void validateSignature(Response response)
throws ValidationException, FileNotFoundException,
CertificateException {
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
try {
profileValidator.validate(response.getSignature());
} catch (ValidationException e) {
/* Indicates signature did not conform to SAML Signature profile */
e.printStackTrace();
throw e;
}
Credential verificationCredential = getVerificationCredential();
SignatureValidator sigValidator = new SignatureValidator(
verificationCredential);
try {
sigValidator.validate(response.getSignature());
} catch (ValidationException e) {
e.printStackTrace();
throw e;
}
}
private Credential getVerificationCredential()
throws FileNotFoundException, CertificateException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
"/pathToYourCertificte"));
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
BasicX509Credential x509Credential = new BasicX509Credential();
x509Credential.setPublicKey(cert.getPublicKey());
x509Credential.setEntityCertificate(cert);
Credential credential = x509Credential;
return credential;
}
}
....................................
saml response in xml file
<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://10.44.90.29:8443/SAMLShareFile/saml/samlresponse" ID="FIMRSP_604af2be-0150-1ff0-adad-8154af08b58c" InResponseTo="-5346144739450824145" IssueInstant="2015-10-13T08:22:15Z" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://10.44.189.168:444/apjct/sps/NewRelic/saml20</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode></samlp:Status><saml:Assertion ID="Assertion-uuid604af281-0150-1512-8c38-8154af08b58c" IssueInstant="2015-10-13T08:22:15Z" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://10.44.189.168:444/apjct/sps/NewRelic/saml20</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="uuid604af289-0150-1dab-a25e-8154af08b58c"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod><ds:Reference URI="#Assertion-uuid604af281-0150-1512-8c38-8154af08b58c"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><xc14n:InclusiveNamespaces xmlns:xc14n="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs saml xsi"></xc14n:InclusiveNamespaces></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod><ds:DigestValue>pMf0E/z1rS9OkTOLc+0aoD7cl30=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>SW9BaJm0rGJAOG62Il1v46YsqocHXNpmcQKAmSIKDX4tRN3EbUHeqFcVfJmmUGDe4uC1H115SOCehQAkJ35lLBnVsda2WHgu4kWdGC8j+kaw0y9zjzngrHZljBpzU2h87zk4X+fGXvtCmBUH7xfrID4tQ6ODdhoWjd6K8s21S50=</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICBzCCAXCgAwIBAgIEQH26vjANBgkqhkiG9w0BAQQFADBIMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGVGl2b2xpMQ4wDAYDVQQLEwVUQU1lQjEYMBYGA1UEAxMPZmltZGVtby5pYm0uY29tMB4XDTA0MDQxNDIyMjcxMFoXDTE3MTIyMjIyMjcxMFowSDELMAkGA1UEBhMCVVMxDzANBgNVBAoTBlRpdm9saTEOMAwGA1UECxMFVEFNZUIxGDAWBgNVBAMTD2ZpbWRlbW8uaWJtLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAiZ0D1X6rk8+ZwNBTVZt7C85m421a8A52Ksjw40t+jNvbLYDp/W66AMMYD7rB5qgniZ5K1p9W8ivM9WbPxc2u/60tFPg0e/Q/r/fxegW1K1umnay+5MaUvN3p4XUCRrfg79OvurvXQ7GZa1/wOp5vBIdXzg6i9CVAqL29JGi6GYUCAwEAATANBgkqhkiG9w0BAQQFAAOBgQBXiAhxm91I4m+g3YX+dyGc352TSKO8HvAIBkHHFFwIkzhNgO+zLhxg5UMkOg12X9ucW7leZ1IB0Z6+JXBrXIWmU3UPum+QxmlaE0OG9zhp9LEfzsE5+ff+7XpS0wpJklY6c+cqHj4aTGfOhSE6u7BLdI26cZNdzxdhikBMZPgdyQ==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID Format="urn:ibm:names:ITFIM:5.1:accessmanager">musaddique</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="-5346144739450824145" NotOnOrAfter="2015-10-13T08:32:15Z" Recipient="https://10.44.90.29:8443/SAMLShareFile/saml/samlresponse"></saml:SubjectConfirmationData></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2015-10-13T08:12:15Z" NotOnOrAfter="2015-10-13T08:32:15Z"><saml:AudienceRestriction><saml:Audience>musaddique</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2015-10-13T08:22:15Z" SessionIndex="uuid604af260-0150-14b6-8127-8154af08b58c" SessionNotOnOrAfter="2015-10-13T09:22:15Z"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="AuthenticatingAuthority" NameFormat="urn:oasis:names:tc:SAML:2.0:assertion"><saml:AttributeValue xsi:type="xs:string">musaddique</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
Your SAML has only assertion part () being signed, so you should get signature from assertion object not response object: try response.getAssertions().get(0).getSignature().
Base on SAML 2.0 specification, SAML response has to be signed, but not both response and sssertion are mandatory.
I wrote this code in my SamlProvider. I didn't used it because the Idp was not requesting the HTTPS protocol and certificates in saml so it's not a "certified solution" I load the certificate from a file so you migth directly inject your BufferedInputStream.
private Credential getCredential() {
BasicX509Credential credential = null;
try {
// read private key
File privateKeyFile = new File(derFile);
FileInputStream inputStreamPrivateKey = new FileInputStream(privateKeyFile);
byte[] encodedPrivateKey = new byte[(int) privateKeyFile.length()];
inputStreamPrivateKey.read(encodedPrivateKey);
inputStreamPrivateKey.close();
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(
privateKeySpec);
// read the certificate
InputStream inStream = new FileInputStream(pemFile);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
// create credential
credential = new BasicX509Credential();
credential.setEntityCertificate((java.security.cert.X509Certificate) cert);
credential.setPrivateKey(privateKey);
} catch (Exception e) {
Logger.error("failed getting credential!", e);
}
return credential;
}
Hope it helps.
Related
We need to send a hash / digest of an XML file to a remote signing service.
The signing service returns a PKCS#7 response. This includes the signature and the short-lived-x509 certificate that was used.
Question: what is the easiest solution to apply the information from the PKCS#7 to the XML file so that it is correctly signed? I am looking for an example (Plain Java or Apache Santuario).
Update:
This is the code used for signing (xml-dsig) an XML with Apache Santuario given a local keystore:
package test.signer.signer;
import org.apache.commons.io.IOUtils;
import org.apache.xml.security.Init;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
/**
* from: https://stackoverflow.com/a/15911581/5658642
*/
public class CreateSignature
{
private static final String PRIVATE_KEY_ALIAS = "sgw-sign-client-keystore";
private static final String PRIVATE_KEY_PASS = "password";
private static final String KEY_STORE_PASS = "";
private static final String KEY_STORE_TYPE = "JKS";
public static void main(String... unused) throws Exception
{
final InputStream fileInputStream = Files.newInputStream(Paths.get("unsigned_DEV.xml"));
try
{
output(signFile(fileInputStream, new File("sgw-sign-client-keystore.jks")), "signed-test.xml");
} finally
{
IOUtils.closeQuietly(fileInputStream);
}
}
public static ByteArrayOutputStream signFile(InputStream xmlFile, File privateKeyFile) throws Exception
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFile);
Init.init();
final KeyStore keyStore = loadKeyStore(privateKeyFile);
final XMLSignature sig = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA);
doc.getDocumentElement().appendChild(sig.getElement());
final Transforms transforms = new Transforms(doc);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
// TODO replace with external signature
final Key privateKey = keyStore.getKey(PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASS.toCharArray());
final X509Certificate cert = (X509Certificate) keyStore.getCertificate(PRIVATE_KEY_ALIAS);
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
sig.sign(privateKey);
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(doc));
return outputStream;
}
private static KeyStore loadKeyStore(File privateKeyFile) throws Exception
{
final InputStream fileInputStream = Files.newInputStream(privateKeyFile.toPath());
try
{
final KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
keyStore.load(fileInputStream, null);
return keyStore;
} finally
{
IOUtils.closeQuietly(fileInputStream);
}
}
private static void output(ByteArrayOutputStream signedOutputStream, String fileName) throws IOException
{
final OutputStream fileOutputStream = Files.newOutputStream(Paths.get(fileName));
try
{
fileOutputStream.write(signedOutputStream.toByteArray());
fileOutputStream.flush();
} finally
{
IOUtils.closeQuietly(fileOutputStream);
}
}
}
This works so far. I now must replace the local keystore with a "remote keystore". The remote signing service takes a digest / hash and signs it. The response is a valid PKCS#7, which contains the certificate and the signature.
I am able to extract both with the following code (based on CMSSignedData from BouncyCastle):
String hashB64 = Base64.getEncoder().encodeToString(digest);
byte[] pkcs7Signature = remoteServiceClientService.sign(hashB64);
CMSSignedData cms = null;
try
{
cms = new CMSSignedData(pkcs7Signature);
SignerInformationStore signers = cms.getSignerInfos();
Collection<SignerInformation> c = signers.getSigners();
for (SignerInformation signer : c) {
// this collection will contain the signer certificate, if present
Collection<X509CertificateHolder> signerCol = cms.getCertificates().getMatches(signer.getSID());
SIG_CERT = new JcaX509CertificateConverter().getCertificate(signerCol.stream().findFirst().get());
}
List<byte[]> signatures = cms.getSignerInfos().getSigners().stream().map(SignerInformation::getSignature)
.collect(Collectors.toList());
byte[] pkcs1Signature = signatures.get(0);
SOPLogger.log("Plain Signature", pkcs1Signature);
return pkcs1Signature;
} catch (CMSException e)
{
throw new RuntimeException(e);
} catch (CertificateException e)
{
throw new RuntimeException(e);
}
I have no idea how to apply the extracted information instead of using a local keystore and are happy to try any hints.
I have the following problem. I wrote simple test class that encrypts and decrypts XML files in java. But when i try to decrypt a file that is loaded from disc, the following error appears:
Oct 04, 2017 5:41:49 PM com.sun.org.apache.xml.internal.security.encryption.XMLCipher doFinal
SEVERE: Source element unexpectedly null...
Exception in thread "main" java.lang.NullPointerException
at com.sun.org.apache.xml.internal.security.encryption.XMLCipher$Factory.newEncryptedData(XMLCipher.java:2190)
at com.sun.org.apache.xml.internal.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1677)
at com.sun.org.apache.xml.internal.security.encryption.XMLCipher.decryptElement(XMLCipher.java:1616)
at com.sun.org.apache.xml.internal.security.encryption.XMLCipher.doFinal(XMLCipher.java:936)
at EncryptionDecryption.decryptDocument(EncryptionDecryption.java:134)
at EncryptionDecryption.main(EncryptionDecryption.java:42)
Class:
import com.sun.org.apache.xml.internal.security.encryption.XMLCipher;
import com.sun.org.apache.xml.internal.security.utils.EncryptionConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
public class EncryptionDecryption {
public static void main(String[] args) throws Exception {
com.sun.org.apache.xml.internal.security.Init.init();
byte[] key = ("i love stackoverflow").getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-512");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Document document = getDocument("classes.xml");
Document encryptedDoc = encryptDocument(document, secretKeySpec,
XMLCipher.AES_256);
saveDocumentTo(encryptedDoc, "encrypted.xml");
encryptedDoc = getDocument("encrypted.xml");
Document decryptedDoc = decryptDocument(encryptedDoc,
secretKeySpec, XMLCipher.AES_256);
saveDocumentTo(decryptedDoc, "decrypted.xml");
}
public static void saveSecretKey(SecretKey secretKey, String fileName) {
byte[] keyBytes = secretKey.getEncoded();
File keyFile = new File(fileName);
FileOutputStream fOutStream = null;
try {
fOutStream = new FileOutputStream(keyFile);
fOutStream.write(keyBytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fOutStream != null) {
try {
fOutStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String keyToString(SecretKey secretKey) {
/* Get key in encoding format */
byte encoded[] = secretKey.getEncoded();
/*
* Encodes the specified byte array into a String using Base64 encoding
* scheme
*/
String encodedKey = Base64.getEncoder().encodeToString(encoded);
return encodedKey;
}
public static SecretKey getSecretKey(String algorithm) {
KeyGenerator keyGenerator = null;
try {
keyGenerator = KeyGenerator.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return keyGenerator.generateKey();
}
public static Document getDocument(String xmlFile) throws Exception {
/* Get the instance of BuilderFactory class. */
DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
/* Instantiate DocumentBuilder object. */
DocumentBuilder docBuilder = builder.newDocumentBuilder();
/* Get the Document object */
Document document = docBuilder.parse(xmlFile);
return document;
}
public static void saveDocumentTo(Document document, String fileName)
throws Exception {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File(fileName));
transformer.transform(source, result);
}
public static Document encryptDocument(Document document, SecretKey secretKey, String algorithm) throws Exception {
/* Get Document root element */
Element rootElement = document.getDocumentElement();
String algorithmURI = algorithm;
XMLCipher xmlCipher = XMLCipher.getInstance(algorithmURI);
/* Initialize cipher with given secret key and operational mode */
xmlCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
/* Process the contents of document */
xmlCipher.doFinal(document, rootElement, true);
return document;
}
public static Document decryptDocument(Document document, SecretKey secretKey, String algorithm) throws Exception {
Element encryptedDataElement = (Element) document.
getElementsByTagNameNS(EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTEDDATA).item(0);
XMLCipher xmlCipher = XMLCipher.getInstance();
xmlCipher.init(XMLCipher.DECRYPT_MODE, secretKey);
xmlCipher.doFinal(document, encryptedDataElement);
return document;
}
}
When i comment out the line 40:
/*encryptedDoc = getDocument("encrypted.xml");*/
Then the problem does not appear. So it's like when i use a xml document encrypted while the program is running without loading from disc, the XMLCipher decrypts it succesfully :)
You need to set your DocumentBuilder to be namespace aware:
public static Document getDocument(String xmlFile) throws Exception {
/* Get the instance of BuilderFactory class. */
DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
builder.setNamespaceAware(true);
// ...
Without this setting the library can't find the metadata it stored when it encrypted the document.
We're trying to make secure http communication between client an server.
The server provided the certificates, we took them, install them and we start running, the point is to exchange an exact number of messages simultaneously between the client and server consecutively, the problem that's driving us crazy is that between the requests, at SSLHANDSHAKE we get randomly the exception javax.net.ssl.SSLException: Received fatal alert: unexpected_message exactly at ServerHello handshake phase, and i don't know how or why this is happening while it keeps working fine for 98% of the other requests.
it crashes at step 2.
Transporter.java : This is the class responsible for sending and receiving the data.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.security.KeyStore;
import java.util.ResourceBundle;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public class Transporter {
private static ResourceBundle resource = ResourceBundle.getBundle("resourece_00");
private static final String keystore = resource.getString("server_keystore");
private static final String truststore = resource.getString("server_truststore");
private static final String keypass = resource.getString("server_keystore_pwd");
private static final String trustpass = resource.getString("server_truststore_pwd");
// secure channel variables
private static SSLSocketFactory sslSocketFactory = null;
public Transporter() {
// setupSocketFactory();
}
static {
try {
String protocol = "TLS";
String type = "JKS";
String algorithm = KeyManagerFactory.getDefaultAlgorithm();
String trustAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
// create and initialize an SSLContext object
SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(getKeyManagers(type, algorithm), getTrustManagers(type, trustAlgorithm), null);
// obtain the SSLSocketFactory from the SSLContext
sslSocketFactory = sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
private static KeyStore getStore(String type, String filename, String pwd) throws Exception {
KeyStore ks = KeyStore.getInstance(type);
InputStream istream = null;
try {
File ksfile = new File(filename);
istream = new FileInputStream(ksfile);
ks.load(istream, pwd != null ? pwd.toCharArray() : null);
} finally {
if (istream != null) {
istream.close();
}
}
return ks;
}
private static KeyManager[] getKeyManagers(String type, String algorithm) throws Exception {
KeyStore ks = getStore(type, keystore, keypass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(ks, keypass.toCharArray());
return kmf.getKeyManagers();
}
private static TrustManager[] getTrustManagers(String type, String algorithm) throws Exception {
KeyStore ts = getStore(type, truststore, trustpass);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(ts);
return tmf.getTrustManagers();
}
public String sendToVD(String msg, String urll, Long timeOut) {
byte[] bytes = msg.getBytes();
HttpsURLConnection sconn = null;
URL url = null;
OutputStream out = null;
BufferedReader read = null;
String recu = null;
try {
url = new URL(urll);
sconn = (HttpsURLConnection) url.openConnection();
sconn.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
sconn.setSSLSocketFactory(sslSocketFactory);
// sconn.setReadTimeout((timeOut.intValue()) * 1000);// set timeout
sconn.setRequestMethod("POST");
sconn.addRequestProperty("Content-Length", "" + bytes.length);
sconn.setRequestProperty("Content-Type", "application/xml; charset=utf-8");
sconn.setDoOutput(true);
sconn.setDoInput(true);
// send POST data
// This is the crash location
out = sconn.getOutputStream();
// OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
out.write(bytes);
out.flush();
// logger.info("flush!!!!!!!!!!!!!");
// out.close();
read = new BufferedReader(new InputStreamReader(sconn.getInputStream()));
String query = null;
recu = read.readLine();
while ((query = read.readLine()) != null) {
recu += query;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// close all connections here
if (out != null)
out.close();
if (read != null)
read.close();
if (sconn != null)
sconn.disconnect();
} catch (Exception ce) {
}
}
return recu;
}
}
The function sendToVD() does the main work of the exchange between the client and the server.
At Client-End :
A web application with JSF managing the front layer, spring managing the beans life cycle, the communication entry to the client is assured by Servlets.
The client is deployed in a RedHat Linux machine, all TLS_VERSIONS are enbaled, JDK_8.
At Server-Side: i can't post the detailed information about the target URL for security measures, but it follows the following pattern https://ip:port/path, and it supports TLS_v1.2.
Hope you can help me out.
I am new to Https Protocol and want to consume soap based web service using apache httpclient.
When I call the web service from Soap UI client it is working fine but when I call same webservice from httpclient with same .jks file It is responding 403 forbidden.
Following is the my httpclient code
import java.io.ByteArrayOutputStream;
import javax.net.ssl.SSLContext;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.KeyManagementException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
public class HttpClientFactory {
private static CloseableHttpClient client;
public HttpClient getHttpsClient() throws Exception {
if (client != null) {
return client;
}
SSLContext sslcontext = getSSLContext();
SSLConnectionSocketFactory factory =
new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy(){
#Override
public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) {
// TODO Implement this method
return 15000;
}
};
client = HttpClients.custom().setSSLSocketFactory(factory).setKeepAliveStrategy(myStrategy).setHostnameVerifier(new AllowAllHostnameVerifier()).build();
return client;
}
public static void releaseInstance() {
client = null;
}
private SSLContext getSSLContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
IOException, KeyManagementException {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream =
new FileInputStream(new File("Test.jks"));
try {
trustStore.load(instream, "password".toCharArray());
} finally {
instream.close();
}
final TrustStrategy trustStrategy = new TrustStrategy() {
public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
for (X509Certificate cer : chain)
printCertificate(cer);
return true;
}
};
return SSLContexts.custom().loadTrustMaterial(trustStore, trustStrategy).build();
}
public static void main(String[] args) {
System.setProperty("javax.net.debug", "ssl:handshake");
CloseableHttpClient httpclient = null;
try {
httpclient = (CloseableHttpClient) new HttpClientFactory().getHttpsClient();
} catch (Exception e) {
e.printStackTrace();
}
HttpPost httpPost = new HttpPost("<POST URL>");
httpPost.setHeader("Accept-Encoding", "gzip,deflate");
httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
httpPost.setHeader("SOAPAction", "");
httpPost.setHeader("Connection", "Keep-Alive");
String payload = Constants.REQUEST;
HttpEntity entity = new StringEntity(payload,HTTP.UTF_8);
httpPost.setEntity(entity);
HttpResponse response = null;
try {
System.out.println("Program started");
response = httpclient.execute(httpPost);
InputStream inputStream = response.getEntity().getContent();
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
inputStream.close();
System.out.println(result.toString("UTF-8"));
} catch (ClientProtocolException e) {
System.out.println("ClientProtocol");
} catch (IOException e) {
System.out.println("IOException");
} finally {
}
}
}
Please help me to get rid of this issue.
I am using WSS4J to create a soap request signer with a certificate from the keystore. My keystore format is .pkcs and everything works with the first signing, but if I try to run the program to sign more than one document and it doesn't find the certificate in the keystore. It seems to me that the certificate is possibly consumed during signing, which means that it no longer exists for the current environment. If the program stops and starts again it will sign the first request but the second request fails. I have stepped through multiple times and cannot figure out what the cause is. This code is the last thing being called before the certificate disappears from the keystore this.certUri = getWsConfig().getIdAllocator().createSecureId("X509-", certs[0]); this is found on line 556 in WSSecSignature.class. Here is my code.
package com.soapsigner;
import java.io.*;
import java.util.Properties;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.ws.security.*;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.Merlin;
import org.apache.ws.security.message.WSSecHeader;
import org.apache.ws.security.message.WSSecSignature;
import org.apache.ws.security.message.WSSecTimestamp;
import org.w3c.dom.Document;
import org.xml.sax.*;
public class SoapSigner {
private Crypto crypto;
private WSSecSignature sig;
private WSSecTimestamp time;
private WSSecHeader header;
private String alias;
private String password;
private String keyFile;
private String keyFileType;
private Document signedDoc;
private String lastError;
{
Logger rootLogger = Logger.getRootLogger();
rootLogger.setLevel(Level.INFO);
rootLogger.addAppender(new ConsoleAppender(
new PatternLayout("%-6r [%p] %c - %m%n")));
}
//constructor
public SoapSigner(String XML){
try {
alias = "myalias";
password = "mypassword";
keyFile = "/keystore/mykeystore.pkcs";
keyFileType = "pkcs12";
sig = new WSSecSignature();
time = new WSSecTimestamp();
header = new WSSecHeader();
signedDoc = null;
lastError = "";
Merlin merlin = new Merlin(getCryptoProperties());
System.out.println("real signing keystore object: "+merlin.getKeyStore().getCertificate(alias).toString().length()); //Passed
crypto = merlin;
signDocument(xmlToDoc(XML));
Merlin test = new Merlin(getCryptoProperties());
System.out.println("test keystore object: "+test.getKeyStore().getCertificate(alias).toString().length()); //Failed, this is null
} catch (Exception e) {
setLastError(e);
}
}
//properties
public Properties getCryptoProperties(){
Properties cryptoProperties = new Properties();
cryptoProperties.setProperty("org.apache.ws.security.crypto.merlin.keystore.alias", alias);
cryptoProperties.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", password);
cryptoProperties.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", keyFileType);
cryptoProperties.setProperty("org.apache.ws.security.crypto.merlin.keystore.file", keyFile);
return cryptoProperties;
}
//sign the document
public void signDocument(Document doc){
try {
header.setMustUnderstand(true);
sig.setSignatureAlgorithm(WSConstants.C14N_EXCL_OMIT_COMMENTS);
sig.setSignatureAlgorithm(WSConstants.RSA);
sig.setUserInfo(alias, password);
sig.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
header.insertSecurityHeader(doc);
sig.build(doc, crypto, header);
time.build(doc, header);
signedDoc = doc;
} catch (Exception e) {
setLastError(e);
}
}
//get the signed document
public Document getDocument(){
return signedDoc;
}
//get the signed xml
public String getXML(){
return getStringFromDoc(getDocument()).trim();
}
//get last error
public String getLastError(){
return lastError;
}
//set last error
private void setLastError(Throwable e){
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
lastError += " NEXT ERROR "+sw.toString();
e.printStackTrace();
}
//document to string
public String getStringFromDoc(Document doc){
try
{
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
writer.flush();
return writer.toString();
}
catch(Exception e)
{
setLastError(e);
return null;
}
}
//string to document
public Document xmlToDoc(String XML){
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db;
db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(XML));
Document doc = db.parse(is);
return doc;
} catch (Exception e) {
setLastError(e);
return null;
}
}
//main
public static void main(String[] args){
String XML1 = "<?xml version='1.0' encoding='UTF-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <soap:Body> <test1></test1> </soap:Body> </soap:Envelope>";
String XML2 = "<?xml version='1.0' encoding='UTF-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <soap:Body> <test2></test2> </soap:Body> </soap:Envelope>";
new SoapSigner(XML1);
new SoapSigner(XML2);
}
}
Also, I would like to turn the doDebug mode on in the WSSecBase.class but it won't showup in the variable viewer to toggle the value. I created a breakpoint in the constructor and set it to be watched but it never shows up to toggle.
Your testcase works fine for me with a .p12 from WSS4J test source on the latest WSS4J SNAPSHOT code. Are you using an older version of WSS4J? If so please try with the latest releases + see if it works. If not, then please create a test-case with your .p12 file + create a new issue in the WSS4J JIRA:
https://issues.apache.org/jira/browse/WSS
Colm.