I am new to C#.NET programming. With help of online references, I have written the code below to verify signature of a SAML assertion (generated by a server API).
My Env:
VS 2010 Ver4.0
Win XP SP3
SAML Assertion token looks something like this:*
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="idGYEv...USb8GfnqF" IssueInstant="2012-12-05T14:13:39.00Z">
<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://noszti...xyz.com</saml:Issuer>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>uDeAjOE/iCa6Pfz5oOjaOMtAQe4=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IGjZX...LaEMzA=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIE...cg6A==</X509Certificate>
<X509SubjectName>emailAddress=xmlsec#aleksey.com,CN=Aleksey Sanin,OU=Test Root Certificate,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US</X509SubjectName>
</X509Data>
</KeyInfo>
</Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">admin</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2012-12-05T14:19:39.00Z" Recipient=""/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2012-12-05T14:13:39.00Z" NotOnOrAfter="2012-12-05T14:19:39.00Z">
<saml:AudienceRestriction>
<saml:Audience/>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2012-12-05T14:13:39.00Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
My code snippet to verify signature:
//Load the SAMLAssertionToken in XML Document
XmlDocument xDoc = new XmlDocument();
xDoc.PreserveWhitespace = false;
xDoc.LoadXml(SAMLAssertionToken); //SAMLAssertionToken above
//Retrieve the public key from certificate available to end user
X509Certificate2 X509Cert = new X509Certificate2("D:/Schemas/X509Certificate.cer");
RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)X509Cert.PublicKey.Key;
//Signature Verification Starts. Find the Signature element
XmlNamespaceManager xMan = new XmlNamespaceManager(xDoc.NameTable);
xMan.AddNamespace("ns", "urn:oasis:names:tc:SAML:2.0:assertion");
xMan.AddNamespace("ns1", "http://www.w3.org/2000/09/xmldsig#");
XmlElement SigElm = (XmlElement)xDoc.SelectSingleNode("//ns:Assertion//ns1:Signature", xMan);
//Create SignedXml object and load signature for verification
SignedXml sig = new SignedXml(xDoc);
sig.LoadXml(SigElm);
bool verified = sig.CheckSignature(rsaKey);
if (verified)
{
Console.WriteLine("Signature verified successfully");
}
else
{
Console.WriteLine("Signature not valid");
}
On running the code, it throws an error "SignatureDescription could not be created for the signature algorithm supplied."
on line: bool verified = sig.CheckSignature(rsaKey);
On debugging, Signature is correctly assigned to SigElm.
Note: the certificate retrieved from "X509Certificate.cer" is exactly the same as that displayed in element of the signature (in SAML Assertion). So it looks like a valid and matching certificate. The certificate in SAML assertion token is signed with a private key; so I am using the public key from "X509Certificate.cer" (certificate available to end users) to verify the signature (in SAML assertion).
I also tried to verify the signature using:
bool verified = sig.CheckSignature(X509Cert, true);
but it throws the same error.
I tried few approaches (using online references for this error) but unable to figure out the problem.
Pls advise...
Related
I want to have the user decide wether to use the standard login or with TOTP.
My Setup:
<add key="ida:SignUpSignInPolicyId" value="B2C_1_signupsignin_1" />
<add key="ida:EditProfilePolicyId" value="B2C_1_profileediting1" />
<add key="ida:ResetPasswordPolicyId" value="B2C_1_passwordreset1" />
In the code do following:
public void SignUpSignInTOTP(string redirectUrl)
{
redirectUrl = redirectUrl ?? "/";
HttpContext.GetOwinContext().Set("Policy", Globals.TOTPPasswordPolicyId);
// Use the default policy to process the sign up / sign in flow
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = redirectUrl });
return;
}
where as
public static string TOTPPasswordPolicyId = ConfigurationManager.AppSettings["ida:TOTPPasswordPolicyId"];
If I set the the TOTPPasswordPolicyId in the ida:SignUpSignInPolicyId it works fine. But if I change it at runtime I get the error.
IDX10501: Signature validation failed. Unable to match keys: kid
I do not understand why this is happening? Any sugestions?
The B2C_1_signupsignin_1 is a user flow and the B2C_1A_TOTP_signup_signin is a custom policy.
Can this maybe be the problem. Is it not possible to mix these?
regards
Stefan
I have metadata provided by service provider.
I am using System.IdentityModel.Metadata; namespace to parse this metadata.
Below is piece of code to parse metadata.
using (XmlReader reader = XmlReader.Create(new StringReader(metadata)))
{
System.IdentityModel.Metadata.MetadataSerializer ser = new System.IdentityModel.Metadata.MetadataSerializer();
var metadataObject = ser.ReadMetadata(reader);
var samlMetadata = ((EntityDescriptor)metadataObject);
entityIdTextBox.Text = samlMetadata.EntityId.Id;
}
I am unable to parse this metadata and getting below error message.
ID3276: The signing credentials cannot be resolved because signed XML does not contain a SecurityKeyIdentifier.
Below is service provider metadata.
<md:EntityDescriptor ID="V.phzM5jUbn3C.zk3RrwXxXaQiH" cacheDuration="PT1440M" entityID="https://PF-DEMO1" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#V.phzM5jUbn3C.zk3RrwXxXaQiH"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>45KpBmol54EyK76KTKqFPMp4aDzzSVCLAu7CZ7SYq8A=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>CmHeuxi5PXdKpVoz3EiWIMa2VyUA49A6GdxokjyEk9Ma2UlWTMD9QM3lExwgtGIhPpjxOJxG2ynF7lFxyp6CvI4DaCsC787K9oo32gth9fCiKJrqgFeX0JSeRjjmZvkwbg+yuj2CMZ+0bAUQNE5cv+QlESetySARQjtx+GUXmAA=</ds:SignatureValue></ds:Signature><md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIB8TCCAVqgAwIBAgIGATDbjNSDMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9RdWljayBTdGFydCBBcHAxEjAQBgNVBAMTCWxvY2FsaG9zdDAgFw0xMTA2MjkxMzE4MTdaGA8yMTExMDYwNTEzMTgxN1owOzELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1F1aWNrIFN0YXJ0IEFwcDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCtsj/v026YKYT/VPBdcK3tfxVdGZ0caA0kmwyr9+5yTVxp4rVGnkgKP+WL5YVaOJU+Wcj75yNvvEYx4/Vgtxhf0NLiGp1pWaEuRrC2aPrmx/0vt/0gdHLaUXq7Jj0cOhSgq+SM/wjKqT/+cED932UblZht3jFOuQvf3bTqosr8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAF9Y0gznNwteCSn8cpgepzgYEgyrZtLJNc2eI5aEl9CwiyV+6oOeXVm1jZjcT9eOfusnJjHzr1AQdHMcDSSRAsevqYnDC9bpvb1SAZJq8HHHFJ7WTQtLLscDGpyPbopOJ2fJUWxkJcjUjmUIJuSwYGKj1l9wkbF1tK2xqjJDPOUR</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://10.164.43.248:9031/sp/SLO.saml2"/><md:AssertionConsumerService index="0" Location="https://10.164.43.248:9031/sp/ACS.saml2" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" isDefault="true"/><md:AttributeConsumingService index="0"><md:ServiceName xml:lang="en">AttributeContract</md:ServiceName><md:RequestedAttribute Name="http://schemas.xmlsoap.org/claims/UPN"/><md:RequestedAttribute Name="http://schemas.auth360.net/2012/01/requestcontext/claims/x-am-mail"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/claims/Group"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"/><md:RequestedAttribute Name="memberOf"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/uid"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/claims/EmailAddress"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"/><md:RequestedAttribute Name="http://schemas.efactum.net/ws/2008/identity/claims/fid"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid"/><md:RequestedAttribute Name="http://schemas.auth360.net/2012/01/requestcontext/claims/x-am-uid"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/claims/CommonName"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"/><md:RequestedAttribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod"/><md:RequestedAttribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"/><md:RequestedAttribute Name="http://schemas.efactum.net/claims/role"/><md:RequestedAttribute Name="http://schemas.efactum.net/claims/emailaddress"/></md:AttributeConsumingService></md:SPSSODescriptor><md:ContactPerson contactType="administrative"/></md:EntityDescriptor>
Please advise for same.
I need to create a digest value for the below input
<u:Timestamp u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<u:Created>2015-07-28T13:35:54Z</u:Created>
<u:Expires>2015-07-28T13:40:49Z</u:Expires>
</u:Timestamp>
so am passing the above value as a doc obj to the below code
public static void main(String[] args) throws Exception {
// Create a DOM XMLSignatureFactory that will be used to generate the
// enveloped signature
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
SecretKey signingKey = new SecretKeySpec("welcome1".getBytes(), "HMAC");
// Create a Reference to the enveloped document (in this case we are
// signing the whole document, so a URI of "" signifies that) and
// also specify the SHA1 digest algorithm and the ENVELOPED Transform.
Reference ref = fac.newReference
("#_0", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform
("http://www.w3.org/2001/10/xml-exc-c14n#", (TransformParameterSpec) null)),
null, null);
// Create the SignedInfo
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.EXCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.HMAC_SHA1, null),
Collections.singletonList(ref));
// Instantiate the document to be signed
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc =
dbf.newDocumentBuilder().parse(new FileInputStream("C:/Users/Signed_Encryp/timestamp.txt"));
// Create a DOMSignContext and specify the DSA PrivateKey and
// location of the resulting XMLSignature's parent element
DOMSignContext dsc = new DOMSignContext
(signingKey, doc.getDocumentElement());
// Create the XMLSignature (but don't sign it yet)
XMLSignature signature = fac.newXMLSignature(si, null);
// Marshal, generate (and sign) the enveloped signature
signature.sign(dsc);
// output the resulting document
OutputStream os;
if (args.length > 1) {
os = new FileOutputStream(args[1]);
} else {
os = System.out;
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
}
which returning me a result as
<u:Timestamp xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="_0">
<u:Created>2015-07-28T13:35:54Z</u:Created>
<u:Expires>2015-07-28T13:40:49Z</u:Expires>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
<ds:Reference URI="#_0">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>1X/3X+yCdJc0x3n8guQnlCFvX+s=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>R4ZrHvlvyGvvQYpojZWPgUgRRSw=</ds:SignatureValue>
</ds:Signature>
</u:Timestamp>
here am not confident that digest value is created using the input am passed, also signature is created inside the timestamp tag , is there any option available to create signature tag after the timestamp tag.
Please help
To check if the signature is over the data, simply change the data and use the same key. If the HMAC value changes then the hash clearly is over the data. When changing back it should return to the old value. Note that this is true for HMAC-SHA1, it may not be the case for all primitives (e.g. RSA-PSS).
Alternatively, if you're up to it, you can perform the canonicalization yourself and manually calculate the signature. Or try another implementation.
If u:Timestamp is the root element then you cannot put anything next to it, as XML only has a single root element. You have yourself indicated that the signature is placed at doc.getDocumentElement(). You can however create a detached signature. Now you know how it is called, you should be able to search for it.
Authentication fails to authenticate for forms authentication in my MVC 5 application. Page gets redirected correctly, but User.Identity.IsAuthenticated and User.Identity.Name values are empty.
My webconfig,
<system.web>
<authentication mode="Forms">
<forms cookieless="UseCookies" defaultUrl="~/" loginUrl="~/user/signin" name="MYAPPWeb" timeout="21600" slidingExpiration="true"/>
</authentication>
UserController,
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult SignIn(SignInViewModel user)
{
UserDTO userObj;
using (var services = new ServiceFactory())
{
userObj = services.UserManagement.ValidateLoginDetails(ConfigHelper.EnvironmentString, user.TenantName, user.Username, user.Password);
}
string userID = userObj.UserID.ToString();
//FormsAuthentication.RedirectFromLoginPage(userID, user.RememberMe);
FormsAuthentication.SetAuthCookie(userID.ToString(),true);
FormsAuthentication.RedirectFromLoginPage(userID, false); //DO NOT REMEMBER ME
}
HomeController (Default page)
public ActionResult Index()
{
bool x = User.Identity.IsAuthenticated; //false?
string y = User.Identity.Name; //null?
return View();
}
It looks pretty straight forward, am I missing something? Please help!
Note:
When I create the project I selected windows authentication. It created some Owin authenticaiton related configuration cs files (startup.auth.cs). I have removed them and added the above appsetting entry as it is required to stop loading Owin assemblies.
<add key="owin:AutomaticAppStartup" value="false"/>
If your project has Owin authentication by default, it will remove form authentication from the project.
If you see your web config you may see
<remove name="FormsAuthentication" />
configuration.
Simply remove it.
I had the same problem and it solved the issue.
Can anyone give me an example how to create new IBM Connections Activity using xPages Social Enabler? I cant find any usefull info in documentation so I have adapted an example from Niklas Heidloff on how to create a new bookmark in Connections. I have the following code for creating a new activity:
try {
var svc = new sbt.ConnectionsService("/activities/service/atom2/activities");
var sb = new java.lang.StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("<entry xmlns:snx=\"http://www.ibm.com/xmlns/prod/sn\" xmlns:opensearch=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:thr=\"http://purl.org/syndication/thread/1.0\" xmlns=\"http://www.w3.org/2005/Atom\">");
sb.append("<title type=\"text\">");
sb.append("test activity from xpages");
sb.append("</title>");
sb.append("<content type=\"html\">");
sb.append("</content>");
sb.append("</entry>");
var msg = svc.post(null, sb.toString(), "xml");
} catch(e) {
print(e)
}
But code above do not create anything but raises error on Domino console. This is returned by svc.post() command:
[31726:00075-3041917840] 11/19/2012 01:03:59 PM HTTP JVM: Client service request to: http://vhost1279.site1.compute.ihost.com:81/activities/service/atom2/activities did not return OK status. Status returned: 415, reason: Unsupported Media Type, expected:information, please consult error-l
[31726:00075-3041917840] 11/19/2012 01:03:59 PM HTTP JVM: g-0.xml located in /local/opt/ibm/lotus/notesdata/domino/workspace/logs
[31726:00075-3041917840] 11/19/2012 01:03:59 PM HTTP JVM: com.ibm.xsp.extlib.sbt.services.client.ClientServicesException: HTTP Status 415, Unsupported Media Type. HTTP error response code received in response to request to url: http://vhost1279.site1.comties/service/atom2/activities
Can anyone give me a hint how to use it properly or point me to some usefull documentation?
Don't use a StringBuilder to create XML. At least use SAX or better Apache Abdera for creating XML (Tutorial here). This ensures that your XML is valid and in case of Abdera also valid ATOM.
It is important to use this approach, since you get a Node object in return, that automatically triggers the needed content type.
Then check how to create an Activity in the Connections documentation wiki (yes - confusing). In this article you find the code to retrieve an activity - I actually recommend to use CURL to get the valid format as an example. Some CURL URLs are here. The closest you get to a full example is Luis' demo of a status update.
To explore connections I use the following batch file:
set server=[server]
set HOME=c:\work
curl %server%%1 –-netrc -G --basic -k -v -L -o %2 %3 %4 %5 %6 %7
with an .netrc file (see the CURL documentation)
machine [server] login [user] password [password]
This is the XML format you need for an activity:
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="activity" label="Activity"/>
<title type="text">Posted activity</title>
<content type="html">
This is an activity that has been automatically uploaded from the cURL command line
</content>
</entry>
And post it like this:
post activities/service/atom2/activities newactivity.xml activityresult.xml
Open the activityresult.xml and locate ocate the href attribute of the app:collection element - you need it to add actions. Use the following XML:
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:snx="http://www.ibm.com/xmlns/prod/sn">
<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="todo"/>
<category term="Connection4.0"/>
<category term="Test"/>
<title type="text">Some things that need to be done</title>
<content type="html">
This is an <b>action</b> in an activity that has been automatically uploaded from the cURL command line.
</content>
<snx:assignedto>noreply#ibm.com</snx:assignedto>
</entry>
and this command:
post [the-url-you-found-above] newaction.xml actionresult.xml
Once the CURL version works you can try yourself using Abdera code.
Here is a working sample from REST client in Firefox:
https://vhost1279.site1.compute.ihost.com/activities/service/atom2/activities
Header: Content-Type application/atom+xml
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:snx="http://www.ibm.com/xmlns/prod/sn" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns="http://www.w3.org/2005/Atom">
<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="activity" label="Activity" />
<content type="html"/>
<title type="text">
test
</title>
</entry>
The problem with the code above is that you pass in a String to the post method. That however doesn't set the right content type. Please use APIs Stephan suggests to create a org.w3c.dom.Node with the XML and pass this in instead. This will set automatically the right content type in the header.
SOLVED!!! I looked to source and problem was obvious. This is rather a bug or at least misconception but can be easily resolved . According the docs and my testing proves this Connections requires the following header in request: Content-Type = application/atom+xml .... but in source code of Social Enabler I found these two related methods:
protected void prepareRequest(HttpClient httpClient, HttpRequestBase httpRequestBase, Options options) throws ClientServicesException {
// TODO: add support for gzip content
//httpClient.addRequestHeader("Accept-Encoding", "gzip");
if(options.getHeaders()!=null) {
addHeaders(httpClient, httpRequestBase, options);
}
if (options.content != null) {
String contentType = null;
HttpEntity entity = null;
Object content = options.content;
try {
//If a subclass overrides com.ibm.xsp.extlib.services.client.Service.processRequestContent(HttpRequestBase, Object, Options)
//the the subclass must set the content type of the request, and also set the request's entity!
if(processRequestContent(httpClient, httpRequestBase, options)){
if (content instanceof IValue) {
JsonFactory jsFactory = new JsonJavaScriptFactory(DesignerRuntime.getJSContext());
entity = new StringEntity(JsonGenerator.toJson(jsFactory, content, true));
contentType = "application/json";
}
else if (content instanceof JsonObject) {
JsonFactory jsFactory = JsonJavaFactory.instanceEx;
entity = new StringEntity(JsonGenerator.toJson(jsFactory, content, true));
contentType = "application/json";
}
else if (content instanceof Node) {
entity = new StringEntity(DOMUtil.getXMLString((Node) content, true));
contentType = "application/xml";
}
else {
entity = new StringEntity(content.toString());
contentType = findRequestTextContentType(options);
}
}
} catch (Exception ex) {
if(ex instanceof ClientServicesException) {
throw (ClientServicesException)ex;
}
throw new ClientServicesException(ex, "Error while parsing request content");
}
if (entity != null && (httpRequestBase instanceof HttpEntityEnclosingRequestBase)) {
httpRequestBase.setHeader("Content-type", contentType);
((HttpEntityEnclosingRequestBase) httpRequestBase).setEntity(entity);
}
}
}
protected String findRequestTextContentType(Options options) {
return "text/plain";
}
As you can see there is no such header (application/atom+xml) for any case. But if you provide XML content as string, the code uses the 'findRequestTextContentType' method to return a default content type, which is 'text/plain' that is not correct for our situation. It is hardcoded so there is no way how to setup the default encoding. But, at least, the 'findRequestTextContentType' is type protected so it can be overriden. So I have created my own ConnectionsService class that extends the former one and overrides the findRequestTextContentType method to return correct content type for my case. And this works fine and resolved the problem !!
import sbt.ConnectionsService;
public class ConnectionsServiceCustom extends ConnectionsService {
public ConnectionsServiceTcl(String serviceUrl) {
super(serviceUrl);
// TODO Auto-generated constructor stub
}
#Override
protected String findRequestTextContentType(Options options) {
return "application/atom+xml";
}
}
As Niklas and Stephen point out you need to use a Dom object (Node, Document etc).. If you are getting an error when creating such an object then it is most likely because the contents of the document/node is poorly formatted or incorrect..
There is a built in XPages util class that allows you to create documents from strings
com.ibm.commons.xml.DOMUtil
Check out
com.ibm.commons.xml.DOMUtil.createDocument(String, String)
e.g.
com.ibm.commons.xml.DOMUtil.createDocument("my xml string", null);
The first parameter is the contents of the XML document, the second is the format.
This class provides several utility methods for parsing and constructing DOM documents.