Validate SAML Response - saml-2.0

I have a SAML response and few other data. Based on this, I need to validate if the response has been tampered or not. How can I do that?
What all I have?
SAML Response with Signed Message & Assertion
IdP EntityId
SP EntityId
SP ACS Endpoint
Target URL
Certificate of the IdP in X509 format.
Language needed: JAVA

Got a solution. If anyone is loking for it.
try {
InputStream is = new FileInputStream("<CERTIFICATE FILE>");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(is);
X509Certificate x509Certificate = (X509Certificate) cert;
PublicKey pk = x509Certificate.getPublicKey();
BasicX509Credential publicCredential = new BasicX509Credential();
publicCredential.setPublicKey(pk);
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
SignableSAMLObject signableSAMLObject = (SignableSAMLObject) <XML OBJECT>;
Signature signature = signableSAMLObject.getSignature();
signatureValidator.validate(signature);
}catch(Exception ex){
// fail this.
}
XML Object can be obtained from SAML Message using marshaller in following way:
String encodedMessage = request.getParameter(PARAM_SAML);
String decodedMessage = new String(Base64.decodeBase64(encodedMessage.getBytes()));
DefaultBootstrap.bootstrap();
BasicParserPool ppMgr = new BasicParserPool();
ppMgr.setNamespaceAware(true);
Document responseRoot = ppMgr.parse(new StringReader(decodedMessage));
UnmarshallerFactory unmarshallFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallFactory.getUnmarshaller(responseRoot.getDocumentElement());
XMLObject obj = unmarshaller.unmarshall(responseRoot.getDocumentElement());

Related

Using ComponentSpace SAML to sign and post request

I am using component space libraries to create SAML request and sign it then post it to URL, However request is not posting successfully because i need to use RSA algorithm key but so far i found that it is not available in SamlKeyAlgorithm also i need to change the Key size to 2048 below are my method that i used to send the request.
private void SendTawtheeqRequest()
{
string ConsumerServiceUrl = "https://tawtheeq.sa:8443/identity-gateway-test/ReceiveSAMLRequest";
// Create a SAML response object.
Response samlResponse = new Response();
// Assign the consumer service url.
samlResponse.Destination = ConsumerServiceUrl;
Issuer issuer = new Issuer(GetAbsoluteUrl("~/"));
samlResponse.Issuer = issuer;
samlResponse.Status = new Status(SamlPrimaryStatusCode.Success, null);
Assertion samlAssertion = new Assertion();
samlAssertion.Issuer = issuer;
// Use the local user's local identity.
Subject subject = new Subject(new NameId(User.Identity.Name));
SubjectConfirmation subjectConfirmation = new SubjectConfirmation(SamlSubjectConfirmationMethod.Bearer);
SubjectConfirmationData subjectConfirmationData = new SubjectConfirmationData();
subjectConfirmationData.Recipient = ConsumerServiceUrl;
subjectConfirmation.SubjectConfirmationData = subjectConfirmationData;
subject.SubjectConfirmations.Add(subjectConfirmation);
samlAssertion.Subject = subject;
// Create a new authentication statement.
AuthnStatement authnStatement = new AuthnStatement();
authnStatement.AuthnContext = new AuthnContext();
authnStatement.AuthnContext.AuthnContextClassRef = new AuthnContextClassRef(SamlAuthenticationContext.Password);
samlAssertion.Statements.Add(authnStatement);
X509Certificate2 encryptingCert = new X509Certificate2(Path.Combine(HttpRuntime.AppDomainAppPath, "my-bank1-public.cer"));
EncryptedAssertion encryptedSamlAssertion = new EncryptedAssertion(samlAssertion, encryptingCert, new EncryptionMethod(SamlKeyAlgorithm.TripleDesCbc));
samlResponse.Assertions.Add(encryptedSamlAssertion);
samlResponse.Assertions.Add(samlAssertion);
samlResponse.SendHttpPost(Response.OutputStream, ConsumerServiceUrl, "10");
}

OpenSAML: Include X509 Certificate in EncyptedAssertion

I am trying to implement IDP initiated SSO using OpenSAML and ComponentSpace acts as SP. The SP is configured to accept a SAMLResponse's with an encrypted Assertion.
I am able to encryt the Assertion but the SP requires me to include X509 Certificate within KeyInfo in the EncryptedData.
Is this possible using OpenSAML?
If Yes, Could you please guide me on how to achieve this?
What SP Expects:
<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>......</X509Certificate>
</X509Data>
</KeyInfo>
<CipherData>
<CipherValue>......</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>......</CipherValue>
</CipherData>
</EncryptedData>
What I am able to generate:
<EncryptedAssertion>
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey>
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<xenc:CipherData>
<xenc:CipherValue>......</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>......</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</EncryptedAssertion>
Check the method signSamlResponseObject2() from http://ideone.com/p4Bhy9.
public void signSamlResponseObject2() {
try {
String keyStoreFileName = "/WEB-INF/classes/saml-data/keystore.jks";
InputStream fis = getServletContext().getResource(keyStoreFileName)
.openStream();
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fis, "abc123456*".toCharArray());
fis.close();
// Get Private Key Entry From keystore
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) ks
.getEntry("zohosso", new KeyStore.PasswordProtection(
"abc123456*".toCharArray()));
PrivateKey privKey = pkEntry.getPrivateKey();
PublicKey pubKey = ks.getCertificate("zohosso").getPublicKey();
X509Certificate cert = (X509Certificate) ks
.getCertificate("zohosso");
/*
* // Getting x509 Certificate from the keystore directly.
*
* KeyStore.TrustedCertificateEntry certEntry =
* (KeyStore.TrustedCertificateEntry) ks .getEntry("zohosso", new
* KeyStore.PasswordProtection( "abc123456*".toCharArray()));
*
* X509Certificate cert = (X509Certificate)
* certEntry.getTrustedCertificate();
*/
// Create a DOM XMLSignatureFactory that will be used to generate
// the
// enveloped signature.
// String providerName =
// System.getProperty("jsr105Provider",JSR_105_PROVIDER);
XMLSignatureFactory sigFactory = XMLSignatureFactory
.getInstance("DOM");
// Create a Reference to the enveloped document (we are
// signing the whole document, so a URI of "" signifies that) and
// also specify the SHA1 digest algorithm and the ENVELOPED
// Transform.
List envelopedTransform = Collections.singletonList(sigFactory
.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null));
Reference ref = sigFactory.newReference("",
sigFactory.newDigestMethod(DigestMethod.SHA1, null),
envelopedTransform, null, null);
SignatureMethod signatureMethod = sigFactory.newSignatureMethod(
SignatureMethod.DSA_SHA1, null);
CanonicalizationMethod canonicalizationMethod = sigFactory
.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null);
// Create the SignedInfo
SignedInfo signedInfo = sigFactory.newSignedInfo(
canonicalizationMethod, signatureMethod,
Collections.singletonList(ref));
// Create a KeyValue containing the DSA PublicKey
KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();
KeyValue keyValuePair = keyInfoFactory.newKeyValue(pubKey);
// Creating the x509 certificate data from Certificate object ( cert )
List x509 = new ArrayList();
x509.add(cert);
X509Data x509Data = keyInfoFactory.newX509Data(x509);
// Create a KeyInfo and add the KeyValue to it
// keyInfoItems.add(Collections.singletonList(keyValuePair));
// Adding the certificate data and the key value pair to the keyInfo
List keyInfoItems = new ArrayList();
keyInfoItems.add(x509Data);
keyInfoItems.add(keyValuePair);
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(keyInfoItems);
// Building the org.jdom.Document object from the samlResponse
// string
// ------------------------------------------------------------------
SAXBuilder builder = new SAXBuilder();
org.jdom.Document doc = builder.build(new ByteArrayInputStream(
strResponseXML.getBytes()));
// ------------------------------------------------------------------
// Convert the rootElement extracted from the doc to w3cElement
// ------------------------------------------------------------------
org.jdom.Element docRootElement = doc.getRootElement();
doc = docRootElement.getDocument();
XMLOutputter xmlOutputter = new XMLOutputter();
StringWriter elemStrWriter = new StringWriter();
xmlOutputter.output(doc, elemStrWriter);
byte[] xmlBytes = elemStrWriter.toString().getBytes();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
org.w3c.dom.Element w3cElement = dbf.newDocumentBuilder()
.parse(new ByteArrayInputStream(xmlBytes))
.getDocumentElement();
// --------------------------------------------------------------------
// Create a DOMSignContext and specify the DSA PrivateKey and
// location of the resulting XMLSignature's parent element
DOMSignContext dsc = new DOMSignContext(privKey, w3cElement);
// compute the correct location to insert the signature xml
// (location is important because the SAML xsd's enforce sequence on
// signed
// info.)
org.w3c.dom.Node xmlSigInsertionPoint = null;
String JSR_105_PROVIDER = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
String SAML_PROTOCOL_NS_URI_V20 = "urn:oasis:names:tc:SAML:2.0:protocol";
org.w3c.dom.NodeList nodeList = w3cElement.getElementsByTagNameNS(
SAML_PROTOCOL_NS_URI_V20, "Extensions");
if (nodeList.getLength() != 0) {
xmlSigInsertionPoint = nodeList.item(nodeList.getLength() - 1);
} else {
nodeList = w3cElement.getElementsByTagNameNS(
SAML_PROTOCOL_NS_URI_V20, "Status");
xmlSigInsertionPoint = nodeList.item(nodeList.getLength() - 1);
}
dsc.setNextSibling(xmlSigInsertionPoint);
// Marshal, generate (and sign) the enveloped signature
XMLSignature signature = sigFactory.newXMLSignature(signedInfo,
keyInfo);
signature.sign(dsc);
// Create the root dom element from the w3cElement using DOMBuilder
DOMBuilder domBuilder = new DOMBuilder();
org.jdom.Element signedElement = domBuilder.build(w3cElement);
doc.setRootElement((org.jdom.Element) signedElement.detach());
xmlOutputter = new XMLOutputter();
strFinalResponse = xmlOutputter.outputString(doc);
System.out.println("The signed SAML Response is : "
+ strFinalResponse);
} catch (Exception e) {
System.out
.println("Exception while attempting to sign the SAML Response.");
e.printStackTrace();
}
}

How do I get a mixed multipart in a RESTEasy response?

I am trying to use resteasy. While I am able to do send a mixed multipart as a request to a webservice, I am unable to do get a mixed multipart in the response.
For eg: Requesting for a file (byte[] or stream) and the file name in a single Response.
Following is what I have tested:
Service code:
#Path("/myfiles")
public class MyMultiPartWebService {
#POST
#Path("/filedetail")
#Consumes("multipart/form-data")
#Produces("multipart/mixed")
public MultipartOutput fileDetail(MultipartFormDataInput input) throws IOException {
MultipartOutput multipartOutput = new MultipartOutput();
//some logic based on input to locate a file(s)
File myFile = new File("samplefile.pdf");
multipartOutput.addPart("fileName:"+ myFile.getName(), MediaType.TEXT_PLAIN_TYPE);
multipartOutput.addPart(file, MediaType.APPLICATION_OCTET_STREAM_TYPE);
return multipartOutput;
}
}
Client code:
public void getFileDetails(/*input params*/){
HttpClient client = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("urlString");
MultipartEntity multiPartEntity = new MultipartEntity();
//prepare the request details
postRequest.setEntity(multiPartEntity);
HttpResponse response = client.execute(postRequest);
HttpEntity returnEntity = response.getEntity();
//extracting data from the response
Header header = returnEntity.getContentType();
InputStream is = returnEntity.getContent();
if (is != null) {
byte[] bytes = IOUtils.toByteArray(is);
//Can we see the 2 parts that were added?
//Able to get a single InputStream only, and hence unable to differentiate two objects in the response
//Trying to see the contents - printing as string
System.out.println("Output from Response :: " + new String(bytes));
}
}
The output is as follows - able to see 2 different objects with different content types, but unable to extract them separately.
Output from Response ::
--af481055-4e4f-4860-9c0b-bb636d86d639
Content-Type: text/plain
fileName: samplefile.pdf
--af481055-4e4f-4860-9c0b-bb636d86d639
Content-Length: 1928
Content-Type: application/octet-stream
%PDF-1.4
<<pdf content printed as junk chars>>
How can I extract the 2 objects from the response?
UPDATE:
Tried the following approach to extract the different parts - use the 'boundary' to break the MultipartStream; use the content type string to extract approp object.
private void getResponeObject(HttpResponse response) throws IllegalStateException, IOException {
HttpEntity returnEntity = response.getEntity();
Header header = returnEntity.getContentType();
String boundary = header.getValue();
boundary = boundary.substring("multipart/mixed; boundary=".length(), boundary.length());
System.out.println("Boundary" + boundary); // --af481055-4e4f-4860-9c0b-bb636d86d639
InputStream is = returnEntity.getContent();
splitter(is, boundary);
}
//extract subsets from the input stream based on content type
private void splitter(InputStream is, String boundary) throws IOException {
ByteArrayOutputStream boas = null;
FileOutputStream fos = null;
MultipartStream multipartStream = new MultipartStream(is, boundary.getBytes());
boolean nextPart = multipartStream.skipPreamble();
System.out.println("NEXT PART :: " + nextPart);
while (nextPart) {
String header = multipartStream.readHeaders();
if (header.contains("Content-Type: "+MediaType.APPLICATION_OCTET_STREAM_TYPE)) {
fos = new FileOutputStream(new File("myfilename.pdf"));
multipartStream.readBodyData(fos);
} else if (header.contains("Content-Type: "+MediaType.TEXT_PLAIN_TYPE)) {
boas = new ByteArrayOutputStream();
multipartStream.readBodyData(boas);
String newString = new String( boas.toByteArray());
} else if (header.contains("Content-Type: "+ MediaType.APPLICATION_JSON_TYPE)) {
//extract string and create JSONObject from it
} else if (header.contains("Content-Type: "+MediaType.APPLICATION_XML_TYPE)) {
//extract string and create XML object from it
}
nextPart = multipartStream.readBoundary();
}
}
Is this the right approach?
UPDATE 2:
The logic above seems to work. But got another block, when receiving the RESPONSE from the webservice. I could not find any references to handle such issues in the Response.
The logic assumes that there is ONE part for a part type. If there are, say, 2 JSON parts in the response, it would be difficult to identify which part is what. In other words, though we can add the part with a key name while creating the response, we are unable to extract the key names int he client side.
Any clues?
You can try the following approach...
At the server side...
Create a wrapper object that can encapsulate all types. For eg., it could have a Map for TEXT and another Map for Binary data.
Convert the TEXT content to bytes (octet stream).
Create a MetaData which contains references to the Key names and their type. Eg., STR_MYKEY1, BYTES_MYKEY2. This metadata can also be converted into octet stream.
Add the metadata and the wrapped entity as parts to the multipart response.
At the Client side...
Read the MetaData to get the key names.
Use the key name to interpret each part. Since the Keyname from the metadata tells if the original data is a TEXT or BINARY, you should be able to extract the actual content with appropriate logic.
The same approach can be used for upstream, from client to service.
On top of this, you can compress the TEXT data which will help in reducing the content size...

Solr Change CommonsHttpSolrServer To HttpSolrServer

For Basic Authentication in solr 3.5 I am using the following code,
String url = "http://192.168.192.11:8080/solr/FormResponses";
CommonsHttpSolrServer server = new CommonsHttpSolrServer( url );
String username = "user";
String password = "user123";
Credentials defaultcreds = new UsernamePasswordCredentials(username, password);
server.getHttpClient().getState().setCredentials(AuthScope.ANY, defaultcreds);
server.getHttpClient().getParams().setAuthenticationPreemptive(true);
In solr 4.0 CommonsHttpSolrServer is not available, so I want to replace it with
HttpSolrServer. Can anyone help me to fix this?
Change the code as follows :
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
String url = "http://192.168.192.11:8080/solr/FormResponses";
HttpSolrServer server = new HttpSolrServer( url );
DefaultHttpClient client = (DefaultHttpClient) server.getHttpClient();
UsernamePasswordCredentials defaultcreds = new UsernamePasswordCredentials("user", "user123");
client.getCredentialsProvider().setCredentials(AuthScope.ANY, defaultcreds);
For server.getHttpClient().getParams().setAuthenticationPreemptive(true) in HttpClient 4 you can use the solution described here.
Finally I find the answer my self,
String url = "http://192.168.192.11:8080/solr/FormResponses";
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials("user", "user123"));
SolrServer solrServer = new HttpSolrServer(url, httpclient);
You need to add the JAR solr-solrj-4.0.0.jar for HttpClientUtil .
Then use below code :
HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr/"+url);
HttpClientUtil.setBasicAuth((DefaultHttpClient) solrServer.getHttpClient(),
"USERNAME", "PASSWORD");
That worked for me.
This is the only way that works for me:
String url = "192.168.192.11:8080/solr/FormResponses";
String username = "user";
String password = "user123";
HttpSolrServer server = new HttpSolrServer("http://" + username + ":" + password + "#" + url);

Box.net api Upload files from Salesforce

I am using the following code to upload the files to Box.net from Salesforce using V2 api and got the following error
System.HttpResponse[Status=Not Found, StatusCode=404]
String sUrl = 'https://upload.box.com/api/2.0/files/data' ;
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(sUrl);
req.setHeader('Authorization', newAuthorization);
req.setMethod('POST');
req.setHeader('Content-Type', 'application/pdf');
String content = '{"filename":"/Users/rmasineni/temp/DealPackage/Cederquist Credit Memo.pdf", "folder_id":"0"}';
//String content = '{"filename":"&", "folder_id":"0"}';
req.setbody(content);
HttpResponse res;
res = h.send(req);
It will be great if someone helps me on how to use Box-api V2 to upload the files .
Thanks,
Rag

Resources