Reputation: 391
I am trying to do signature validation on SAML2 Response which is obtained from an identity provider using OpenSAML. I am trying to read the response from the localfile system.
Here is my code:
DefaultBootstrap.bootstrap();
BasicParserPool ppMgr = new BasicParserPool();
ppMgr.setNamespaceAware(true);
//Read file from the filesystem
File file1=new File("F:/Softwares/Assertion.xml");
InputStream inCommonSaml=new FileInputStream(file1);
// Parse file
Document inCommonSamlDoc = ppMgr.parse(inCommonSaml);
Element metadataRoot = inCommonSamlDoc.getDocumentElement();
UnmarshallerFactory unmarshallerFactory=configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot);
Response inCommonSamlRes = (Response) unmarshaller.unmarshall(metadataRoot);
//Get certificate
SignatureValidator signatureValidator = new SignatureValidator(cert);
Signature signature=inCommonSamlRes.getSignature();
signatureValidator.validate(signature);
try {
BasicX509Credential credential = new BasicX509Credential();
File file2=new File("F:/Softwares/publicKey.crt");
InputStream samlCertificate=new FileInputStream(file2);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//
@SuppressWarnings("deprecation")
java.security.cert.X509Certificate certificate = (java.security.cert.X509Certificate) certificateFactory.generateCertificate(samlCertificate);
//
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec((certificate).getPublicKey().getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(publicKeySpec);
credential.setPublicKey(key);
Object obj = (credential).getPublicKey();
if (obj instanceof RSAPublicKey) {
BigInteger modulus = ((RSAPublicKey) obj).getModulus();
BigInteger exponent = ((RSAPublicKey) obj).getPublicExponent();
System.out.println("modulus");
System.out.println (org.apache.commons.codec.binary.Base64.encodeBase64String(modulus.toByteArray()));
System.out.println("public exponent:");
System.out.println (org.apache.commons.codec.binary.Base64.encodeBase64String(exponent.toByteArray()));
}
// System.out.println ("public key is: //n//r"+ credential.getPublicKey());
return credential;
} catch (Exception e) {
throw e; //Throws a 'Signature did not validate against the credential's key' exception
}
Note: I use the same certificate(publicKey.crt) to sign the assertion also.
I am getting the following error:
signature cryptographic validation not successful.
Please let me know where am I wrong? What does the error mean? Does it say that public and private keys are the same?
Thanks, aswini J
Upvotes: 1
Views: 8790
Reputation: 4786
This answer is for incoming people getting this error and searching on Google.
In my case, I am facing the same error :"error: signature cryptographic validation not successful", with a slightly different case. I am validating with SimpleSamlPHP as SP and CAS as IDP.
The problem was that my SP uses one (self-signed) cert for SP validation to IDP, and another cert for SP in Apache to make allow SSL (so that I can have https)
Using two separate cert might works fine for a lot of process like login and metadata validation, but with prcess like logout the above error will happen.
The solution is to use only one cert for both process, and my error is gone.
Upvotes: 0
Reputation: 11975
I think you need to get .jks file from IdP (Identity Provider) server. Also when you're getting SAMLResponse from for your POST from IDP, this SAMLResponse should be containing Signature (FYI - will be an encoded string, you can decode and read using Open SAML library, available on Maven Central Repository). Once you get signature from , you can validate that using OpenSAML
sigValidator.validate(response.getSignature());
This method will give you meesage if everything is OK. The message for reference "Signature validated with key from supplied credentia"
You can follow this link: http://sureshatt.blogspot.in/2012/11/how-to-read-saml-20-response-with.html to get Signature and
(IMP): Your IDP (Identity Provider) should be send (may be via HTTP POST), so that you can get from which can have NameID i.e, ClinetId
Upvotes: 1