Reputation: 1475
I'm tried to implement SSO for SalesForce using OpenSAML. My code generates valid SAML assertion, which validated by salesforce SAML validator. But when I tried to send assertion to salesforce I always got this error:
{"error_uri":"https://na4.salesforce.comnull/setup/secur/SAMLValidationPage.apexp","error":"invalid_grant","error_description":"invalid assertion"}
I using folloving code to send request to salesforce:
SAMLResponseGenerator responseGenerator = new SalesforceSAMLResponseGenerator(container, strIssuer, strNameID, strNameQualifier, sessionId);
String samlAssertion = Base64.encodeBase64String(responseGenerator.generateSAMLAssertionString());
try {
HttpClient httpClient = createHttpClient();
HttpPost httpPost = new HttpPost("https://login.salesforce.com/services/oauth2/token");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("grant_type", new StringBody("assertion"));
entity.addPart("assertion_type", new StringBody("urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser"));
entity.addPart("assertion", new StringBody(samlAssertion));
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
String line = null;
while ((line = rd.readLine()) != null) {
buffer.append(line);
buffer.append("\n");
}
rd.close();
httpClient.getConnectionManager().shutdown();
System.out.println(buffer.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
My generator generated valid SAML (If I can trust salesforce SAML validator results). Seems that salesforce can't decode assertion, because when I sent random data instead of samlAssertion I've recieved same error message.
I also tried to use Base64.encodeBase64URLSafeString() to encode but without positive results.
Can anyone help me with this issue?
Upvotes: 3
Views: 1436
Reputation: 1475
Solution of my problem was very simple. Do not trust SalesForce's documents, trust only protocol specs :) According to specs I needs to send Base64 encoded SAML in SAMLResponse parameter. That is all.
I've using following code illustrated the solution:
HttpClient httpClient = initHttpClient();
HttpPost httpPost = new HttpPost("https://login.salesforce.com/");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.STRICT);
entity.addPart("SAMLResponse", new StringBody(Base64.encodeBase64String(samlAssertion)));
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
Header location = httpResponse.getFirstHeader("Location");
if (null != location) {
System.out.println(location.getValue());
}
Upvotes: 2