Archive for January, 2008

How to use Java Web21c SDK from Scala

It is an example how to use the Web21c SDK from a Scala application.

First couple of words about Scala. Scala was created in 2001 at the École Polytechnique Fédérale de Lausanne (EPFL) in Switzerland. It is platform independent, multi-paradigm language which integrates features of object-oriented and functional programming, is type-safe (but you don’t have to define redundant types of information) and extensible (good candidate for DSLs). It brings a lot of very nice syntactical sugar as well! As Scala smoothly integrates with Java and .Net worlds we can run Scala applications on JVM or .NET CLR and easily reuse existing libraries for those platforms.

One of those libraries is Web21c SDK which gives us easy way of integrating communication services and comes in couple of flavours: SDK for Java, .Net, Python and PHP. We could integrate Scala with Java or .NET SDK but for the purpose of this example we will see how easy it is to incorporate Java SDK into our Scala application.

Let’s assume we use Scala plugin for Eclipse and we created a new Scala project.

We can get the latest Web21c SDK for Java and before proceeding to next steps we have to register our application and obtain own certificate for sandbox server which is free. Then we will create two folders: lib and resources in our project and we will unzip content of the Web21C-JavaSDK-5.0.zip and copy content of the lib folder from SDK to our lib folder. Let’s copy the Web21C-JavaSDK-5.0.jar there as well. We will copy previously obtained certificate to the resources folder and we will create a properties file called security.properties where you can store name of your cert and its password:

org.apache.ws.security.crypto.provider=com.bt.security.PKCS12Crypto
org.apache.ws.security.crypto.merlin.keystore.type=pkcs12
org.apache.ws.security.crypto.merlin.keystore.password=YOUR_CERTIFICATE_PASSWORD
org.apache.ws.security.crypto.merlin.alias.password=YOUR_CERTIFICATE_PASSWORD
org.apache.ws.security.crypto.merlin.file=YOUR_CERTIFICATE.pfx

constants.provider=com.bt.sdk.common.SandboxConstants

Next from Eclipse in the project Properties/Java Build Path/Source/Add Folder… we will add resources folder to the classpath and all jars from lib folder to the Properties/Java Build Path/Libraries/Add JARs… to place them on the classpath as well. We should be good to go.

Then we will create the Scala singleton where we will use directly Java objects. For example Manager classes for one of the Web21c services, for instance One Way Messaging to create a simple sms client (src/SmsClient.scala):

import com.bt.sdk.capabilities.messaging.oneway.MessagingOneWayManager

object SmsClient {
    def main(args: Array[String]) {
        new MessagingOneWayManager().sendMessage("tel:44xxxxxxxxx", "Hello World")
    }
}

Or even simpler:

import com.bt.sdk.capabilities.messaging.oneway.MessagingOneWayManager

object SmsClient extends Application {
    new MessagingOneWayManager().sendMessage("tel:44xxxxxxxxx", "Hello World")
}

Is that close to the famous “one line of code”?

Our project’s structure should look more or less like:

+ Web21cAndScala
    L---+ src
        L--- Web21c.scala
    L---+ bin
        L--- //compiled classes
    L---+ lib
        L--- Web21C-JavaSDK-5.0.jar
        L--- //other jars from lib folder
    L---+ resources
        L--- sandbox.pfx
        L--- security.properties

We are ready to try if it works. Try Run As… Scala Application. Great if it works! If you get following error:

Exception in thread "main" Reporting Service: Unknown
com.bt.sdk.ServiceException: Unknown exception encountered: java.lang.ExceptionInInitializerError
null
    at com.bt.sdk.capabilities.messaging.oneway.MessagingOneWayManager.<init>(MessagingOneWayManager.java:26)
    at SmsClient$.main(SmsClient.scala:7)
    at SmsClient.main(SmsClient.scala)

Then it means that folks from Lausanne haven’t fixed the bug in Scala Eclipse Plugin yet. It simply doesn’t copy resources on the classpath to the output folder (bin) and the Web21c Java SDK can’t see security.properties and the certificate. For purposes of this exercise you can simply copy content of the resources folder to the bin folder. As hot fix you could also create an ant task similar to the one below. You can make the execution of one or more targets from an Ant build part of the normal build of your project:

<?xml version="1.0" encoding="UTF-8"?>
<project name="copyprops" default="default" >
    <target name="default" >
        <copy todir="${basedir}/bin">
            <fileset dir="${basedir}/src" includes="**/*.*" excludes="**/*.scala"/>
        </copy>
    </target>
</project>

I know that it is very simple demo but I hope it will be of any use for someone. Let me know if you are having any issues with the sample. And remember that Sandbox Usage is restricted.

Popularity: 65% [?]

Comments

Lookout search plugin and Outlook 2007

LookoutIf you have to use Outlook I believe you deserve better search features than the features available for you by default. Many of you know the great search plugin Lookout. However after migrating to Outlook 2007 I was unable to successfuly install and use it. Instead after restarting Outlook I got error message:

Sorry! It looks like another Outlook Plugin has installed an unofficial version of the Outlook libraries which breaks Lookout. Lookout will not be able to load. […].

But it looks like there is a way to install Lookout on Outlook 2007. After closing Outlook run from command line:

cd  %SYSTEMROOT%\assembly\GAC

rename Microsoft.Office.Interop.Outlook Microsoft.Office.Interop.Outlook.OLD

type nul > Microsoft.Office.Interop.Outlook

rename Policy.11.0.Microsoft.Office.Interop.Outlook Policy.11.0.Microsoft.Office.Interop.Outlook.OLD

After restarting Outlook everything should work. Don’t blame me if it doesn’t. But in case it doesn’t you can revert changes executing following commands:

cd  %SYSTEMROOT%\assembly\GAC

rename Policy.11.0.Microsoft.Office.Interop.Outlook.OLD Policy.11.0.Microsoft.Office.Interop.Outlook

del Microsoft.Office.Interop.Outlook

rename Microsoft.Office.Interop.Outlook.OLD Microsoft.Office.Interop.Outlook

Hope it helps!

Popularity: 75% [?]

Comments (6)

Ubuntu clearly the winner

Linux distros trends

I used Google Trends to check which Linux distribution is the most popular among Google search users. As you could probably easily guess and what is visible on the diagram Ubuntu is clearly the winner at the moment with the biggest number of search requests. What is interesting is that at the beginning of 2003 there were at least three equally popular distributions: Debian, Suse (now OpenSuse) and Mandrake (now Mandriva) with Red Hat slightly behind. Situation changed since then though. Debian sort of maintains its share. But other distributions became less and less popular with Mandrake loosing the most but partially probably due to changed name. Ubuntu with its excellent online community gains attention with linear search volume increase. I hope it will remain like that and then it is a matter of time when Windows with its ridiculous Vista release will go to hell.

Popularity: 39% [?]

Comments (4)

Megaman vs Polish immigrant

I want to talk today about new ways of expressing opinions and reaching to people using example of a tragic accident which happened last year in Canada.

On October 14, 2007, Robert Dziekanski, 40 years old Polish immigrant who arrived at the Vancouver International Airport has died shortly after being tesered and subdued by the Royal Canadian Mounted Police (RCMP) after waiting 10 hours at the airport and becaming visibly agitated. According to police Dziekanski “continued to throw things around and yell and scream”, after the arrival of the police officers, which was later revealed to be false in the video. RCMP was heavily criticized for providing a false version of events prior to the public release of the video. It was very unfamous incident which triggered big debate concerning police use of tasers and about the way how RCMP handled the situation. Just to mention that Dziekanski has been teasered second time after failling to the ground which completely doesn’t make any sence to me. Some eyewitnesses claim that he has been tesered as many as four times.

Couple of days ago this case came back to the headlines again. This time because of a video which appeared on YouTube that “parodies” the incident. The video, created by Vancouver resident Mike Greenway, titled Megaman vs. Polish Immigrant shows the 1980s video game character Megaman tasering an opponent (Mr. Dziekanski) after choosing option “Taser Mercilessly”.

As we could expect the reaction to the video was mixed. Media in Canada and Poland has been indignant at the video calling it more than offensive. Similarly a spokesman for the RCMP said he found the video offensive blaming the online culture for emerging such thing on the Internet: “Any right-thinking person who would look at the video would be offended by that. A gentlemen lost his life and it is in extremely poor taste” said sgt. John Ward. Lost his life? Hmmm… Rather you took it. On the other hand there are opinions that the video in the form of parody is really a statement on police taser use, not a cheap entertainment for crowds. The author Mike Greenway said that “The video that I made is a tongue-in-cheek parody about the incompetence of everyone involved, not police brutality.”

Why then that video has been so controversial? Because it’s been intended to be. Someone could say that Greenway crossed a border of a good taste when he has chosen the infantile form of an old game to make a comment on that event. But to make a point we have to reach sometimes for such tools to trigger discussion, to be controversial in sake of reaching bigger audience. I am really happy to live in current times when everyone via forums, blogs, videos, twitts etc. has a chance of forming independent thoughts and independent conversations. A spokeswoman for the Polish Embassy in Canada, Marta Grywalska said: “The public was disturbed by the event. This is how the subculture reacted to it”. Well said. But it is not a subculture anymore. We have own voice. We are the mainstream now.

Popularity: 52% [?]

Comments (1)

How to verify digital signatures of XML documents without WSE3

Joshua Watkins, Piotr Woloszyn

Just before Christmas Josh Watkins and me had to face the interesting task of removing the dependency on Microsoft Web Services Enhancements (WSE) 3.0 in one of the projects that we are working on currently. The task consisted of two parts: signing the soap requests and validating incoming soap responses. Thanks to Robbie’s spike for signing requests we managed to quickly finish the first task. I might blog about this as well soon. The second one is a different story. As this turned out to be a pain in the butt and we couldn’t find easily comprehensive information about verifying XML’s digital signatures on the web we decided to share our finding with wider audience and hopefully help someone who has to face the same challenge. Alors…

Josh: I would just like to add that it was a really really … really big pain in the butt.

XML digital signatures (XMLDSIG) allow you to verify that data was not altered after it was signed. Working in the Microsoft .NET 2.0 world it wouldn’t be difficult as we could use the SignedXml class as described here:

// Verify the signature of an XML file against an asymmetric

// algorithm and return the result.

public static Boolean VerifyXml(XmlDocument Doc, RSA Key)

{
    // Create a new SignedXml object and pass it
    // the XML document class.
    SignedXml signedXml = new SignedXml(Doc);    // Find the "Signature" node and create a new

    // XmlNodeList object.
    XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");

    // Load the first <signature> node.
    signedXml.LoadXml((XmlElement)nodeList[0]);

    // Check the signature and return the result.
    return signedXml.CheckSignature(Key);
}

Unfortunately the signed soap responses were hashed with SHA256 algorithm defined as:

<signaturemethod algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256">

And that algorithm is unsupported:

With the 2.0 release of the CLR, there is no way to use the RSA-SHA256 signature type with SignedXml. Adding a SHA-256 CryptoServiceProivder implemenation is high on our list of items to look at in the next version, which should enable this scenario.

- Shawn Farkas, Microsoft, 09/09/2007

Josh: When we first tried using the SignedXML method we would get a malformed Reference Element error (or something like that). Which as you can imagine, isn’t really all that helpful or descriptive.

The only available option was to verify the signature manually. Before we will get to details how to do it let’s look at the XML of the SOAP response coming back to us. As we can see there is Signature element which has the children SignedInfo and SignatureValue. SignedInfo holds information about which parts of the message have been signed, with which algorithm, and the hash of the signed element. No one will be able to tamper with the content of the nodes (in this example we sign soap:Body, wsu:Timestamp, wsse:BinarySecurityToken) without being detected through varying hash values. The SignatureValue is the content of the SignedInfo node hashed and signed with the private key of sender, so we can trust the content of that node as well. The whole problem is in the step which has to be performed before hashing: Canonicalization of the XML. Getting the process right for c14n was the most time consuming part.

Now more details and some code. Let’s assume that we implement System.Web.Services.Protocols.SoapExtension and will verify the message in overriden ProcessMessage(SoapMessage message) method, stage SoapMessageStage.BeforeDeserialize. Let’s assume as well that we have the content of the soap message as string (messageContent). To verify the digital signature of an XML document:

1. Create XmlDocument using the messageContent:

XmlDocument xDoc = new XmlDocument();

xDoc.PreserveWhitespace = false;

xDoc.LoadXml(messageContent);

2. Load the server certificate from file system:

X509Certificate2 serverCertificate = new X509Certificate2(pathToServerCert);

3. Now let’s validate message signature. Move to SignatureValue node using the lovely XPathNavigator:

XPathNavigator nav = xDoc.CreateNavigator();

nav.MoveToFollowing("SignatureValue", "http://www.w3.org/2000/09/xmldsig#");

4. The signature value requires that all of the \n inserted into the value are removed before we processed it:

string signatureValue = Regex.Replace(nav.InnerXml.Trim(), @"\s", "");

5. The signature value is saved in the messages encoded in base64. Therefore to get the actual signature value we have to convert back from base64:

byte[] sigVal = Convert.FromBase64String(signatureValue);

6. The SignedInfo XML block is extracted from the greater document. Then we take out all of the namespaces used in all of the parent nodes of SignedInfo and then reinsert them into the SignedInfo block. Without this your validation will FAIL.

Josh: And our validation did indeed fail every time without this. J

XmlNode signedInfo = xDoc.GetElementsByTagName("ds:SignedInfo")[0];
Hashtable ns = RetrieveNameSpaces((XmlElement)signedInfo);
InsertNamespacesIntoElement(ns, (XmlElement)signedInfo);

where:

public static Hashtable RetrieveNameSpaces(XmlElement xEle)
{
    Hashtable foundNamespaces = new Hashtable();
    XmlNode currentNode = xEle;
    string name = null;

    while (currentNode !=null)
    {
        //add namespace for current nodes namespace if it has one.
        if (currentNode.NodeType == XmlNodeType.Element && !String.IsNullOrEmpty(currentNode.Prefix))
        {
            if (!foundNamespaces.ContainsKey("xmlns:" + currentNode.Prefix))
            {
                foundNamespaces.Add("xmlns:" + currentNode.Prefix, currentNode.NamespaceURI);
            }
        }

        //now we add namespaces for any attributes that this node may have.
        if (currentNode.Attributes !=null && currentNode.Attributes.Count>0)
        {
            for (int i=0; i< currentNode.Attributes.Count;i++)
            {
                if (currentNode.Attributes[i].Prefix.Equals("xmlns") || currentNode.Attributes[i].Name.Equals("xmlns"))
                {
                    if (!foundNamespaces.ContainsKey(currentNode.Attributes[i].Name))
                    {
                        foundNamespaces.Add(currentNode.Attributes[i].Name, currentNode.Attributes[i].Value);
                    }
                }
            }
        }
        currentNode = currentNode.ParentNode;
    }
    return foundNamespaces;
}

public static void InsertNamespacesIntoElement(Hashtable namespacesHash, XmlElement node)
{
    XPathNavigator nav = node.CreateNavigator();
    if (String.IsNullOrEmpty(nav.Prefix) && String.IsNullOrEmpty(nav.GetAttribute("xmlns","")))
    {
        nav.CreateAttribute("", "xmlns","",nav.NamespaceURI);
    }
    foreach (DictionaryEntry namespacePair in namespacesHash)
    {
        string[] attrName = ((string)namespacePair.Key).Split(':');
        if (attrName.Length > 1 && !node.HasAttribute(attrName[0]+":"+attrName[1]))
        {
             nav.CreateAttribute(attrName[0], attrName[1], "", (string)namespacePair.Value);
        }
    }
}

7. Canonicalize the signedInfo:

Stream signedInfoStream = canonicalizeNode(signedInfo);

where:

public static Stream canonicalizeNode(XmlNode node)
{
    XmlNodeReader reader = new XmlNodeReader(node);
    Stream stream = new MemoryStream();

    XmlWriter writer = new XmlTextWriter(stream, Encoding.UTF8);

    writer.WriteNode(reader, false);
    writer.Flush();

    stream.Position = 0;

    //To ensure that the XML is properly formatted we use this transform on it
    // before creating the hash of the SignedInfo block.
    XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
    transform.LoadInput(stream);
    return (Stream)transform.GetOutput();
}

8. The next step is to compute the hash of the canonicalized signedInfo:

SHA1 sha1 = SHA1.Create();
byte[] hashedSignedInfo = sha1.ComputeHash(signedInfoStream);

9. The last step of the validation of the message signature is to verify the hash using a crypto service provider via the sender’s public key:

string oid = CryptoConfig.MapNameToOID("SHA1");
RSACryptoServiceProvider crypto = (RSACryptoServiceProvider)cert.PublicKey.Key;
bool isMessageSignatureValid = crypto.VerifyHash(hashedSignedInfo, oid, sigVal);

10. OK, if we got so far it means that nobody tempered with the SignedInfo node. Now we have to validate if no one tempered with content of signed elements by inspecting references and hashes in the SignedInfo. That’s the place where the SHA256 algorithm is used. First let’s load the message references from the SingedInfo node:

XmlNamespaceManager man = new XmlNamespaceManager(xDoc.NameTable);
man.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
man.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
man.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");

// A bit of xpath to only get the reference nodes in the security header.
XmlNodeList messageReferences = xDoc.SelectNodes("//soap:Header/wsse:Security/ds:Signature/ds:SignedInfo/ds:Reference", man);

11. For each of the references we shall perform validation (steps 12-17). First we will look up the reference listed in SignedInfo and retrieve the correspodning node from the xDoc.

XPathNavigator elementNav = xEle.CreateNavigator();
string elementID = elementNav.GetAttribute("URI", "");
//We need to remove the hash. :)
if (elementID.StartsWith("#"))
{
    elementID = elementID.Substring(1);
}

12. Now we find the node associated with the id.

XmlElement referencedNode = retrieveElementByAttribute(xDoc, "wsu" + ":Id", elementID);

where:

public static XmlElement retrieveElementByAttribute(XmlNode xDoc, string attributeName, string attributeValue)
{
    ParameterValidation.Validate("xDoc", xDoc);
    ParameterValidation.Validate("attributeName", attributeName);
    ParameterValidation.Validate("attributeValue", attributeValue);

    XmlElement foundElement = null;
    foreach (XmlNode node in xDoc)
    {
        if (node.HasChildNodes)
        {
            foundElement = retrieveElementByAttribute(node, attributeName, attributeValue);
        }
        if (foundElement == null && node.Attributes != null && node.Attributes[attributeName] != null && node.Attributes[attributeName].Value.Equals(attributeValue))
        {
            foundElement = (XmlElement)node;
            break;
        }
        if (foundElement != null)
        {
            break;
        }
    }
    return foundElement;
}

13. Then we will incorporate the namespaces from the parent node of the retrieved node

InsertNamespacesIntoElement(RetrieveNameSpaces((XmlElement)referencedNode.ParentNode), referencedNode);

14. Now we will canonicalize the node with the specified canonicalization method.

Stream canonicalizedNodeStream = canonicalizeNode(referencedNode);

15. Create the proper hash algorithm object and compute the hash of the signed node:

elementNav.MoveToFollowing("DigestMethod", "http://www.w3.org/2000/09/xmldsig#");
HashAlgorithm hashAlg = (HashAlgorithm)CryptoConfig.CreateFromName(elementNav.GetAttribute("Algorithm", ""));
byte[] hashedNode = hashAlg.ComputeHash(canonicalizedNodeStream);

16. Load the digest value and decode its value using base64 encoding:

elementNav.MoveToFollowing("DigestValue", "http://www.w3.org/2000/09/xmldsig#");
byte [] digestValue = Convert.FromBase64String(elementNav.InnerXml)

17. If the hashedNode array and the digestValue array are equal then the verification of the reference from the SignedInfo is positive! After repeating this for all the references the verification of the digital signatures of XML documents, without using WSE3 is done.

Josh: It all seems so easy now. I think the hardest part of this entire process is never really knowing if you are on the right path until you get it completely right. Hopefully this tutorial will help someone else avoid the pain and suffering that we had to endure.

Some other useful links:
Apache XML Security
An Introduction to XML Digital Signatures
Bouncy Castle

PS. REST rulez!

Popularity: 62% [?]

Comments (2)

Close
E-mail It