Man in the Mirror, Apple’s Security Flaw, and the Importance of Unit Testing

The “Man-in-the-Middle” attack is such a well-recognized security risk, with established solutions and preventative measures in place that when I first heard about the recent ruckus around the Apple security flaw, I thought Apple’s trouble was more legal in natural, maybe some sort of royalties dispute between iTunes and the Michael Jackson estate. Only later did I found out what all the fuss was about “in the middle”, not “in the mirror”, and why I had to upgrade the iOS on my iPhone on a beautiful Saturday afternoon.

Regarding the specifics to Apple’s security flaw, there is already plenty of press coverage out there.  For example, David Auerbach wrote a great analysis over at Slate.com.

In this post, I’d like to illustrate how automated unit testing with appropriate code coverage could have detected that particular kind of error, the one caused by grammatically correct code that inadvertently invalidated the whole logic of the program. We will build the unit tests using the module, an open source Mule testing framework that significantly streamline and simplify the process of writing unit tests.

We have built a simple, demonstrative application that processes incoming messages differently depending on whether a property of the payload, called “goodguy”, has value of “true” or not. If the value was true, the message would be processed one way and an HTTP 200 status would be returned. If it was not, the message would be processed another way and an HTTP status 400 would be returned:

The key logic for routing the message is shown below:

<choice doc:name="Choice">
  <!-- <when expression="#[payload['goodguy']=true]"> -->
  <when expression="#[payload['goodguy']==true]">
    <set-payload value="#['All Good']" doc:name="set-valid-payload-response"/>
    <http:response-builder status="200" contentType="text/plain" doc:name="HTTP Response 200"/>
  </when>
  <otherwise>
    <set-payload value="#['Invalid Payload']" doc:name="invalid-payload-goes-here"/>
    <http:response-builder status="400" contentType="text/plain" doc:name="HTTP Response 400"/>
  </otherwise>
</choice>

Let’s assume the initial release of the application had passed manual end-to-end testing and UAT and had been deployed to production:

Now let’s pretend that over time, additional features had to be added to the application so the code had to be touched again, and a developer had accidentally changed the double “==” to just a single “=” in the expression in the Choice router. If there was no unit testing, the application would package successfully, deployment would go smoothly, and the application would actually run, but just not processing the messages correctly:


However, if unit testing with sufficient code coverage was put in place:

<!--Beginning of First Test, Generally the Happy Path where payload values are expected / valid-->
<munit:test name="ValidateHappyPath" description="Test when input is as expected">
	<!--Mock inbound endpoint since it is a unit test-->
	<mock:when messageProcessor="http:inbound-endpoint"/>
	<!--Now set the payload to have the valid value-->
	<munit:set payload-ref="#['']">
		<munit:inbound-properties>
			<munit:inbound-property key="flag" value-ref="#['true']"/>
		</munit:inbound-properties>
	</munit:set>
	<!--Pass the payload into the flow to be unit-tested-->
	<flow-ref name="munit-demo-flow"/>
		
	<!-- Assert the flow behaved as designed for a valid payload -->
	<munit:assert-on-equals expected-ref="#[200]" value-ref="#[payload.getStatusCode()]"/>
</munit:test>
<!--End of First Test-->
<!--Beginning of Second Test, Generally the Sad Path where payload values are unexpected / invalid-->
<munit:test name="ValidateSadPath" description="Test when input is not as expected and error should be thrown">
	<!--Mock inbound endpoint since it is a unit test-->
	<mock:when messageProcessor="http:inbound-endpoint"/>
	<!--Now set the payload to have the invalid value-->
	<munit:set payload-ref="#['']">
		<munit:inbound-properties>
			<munit:inbound-property key="flag" value-ref="#['qwerty']"/>
		</munit:inbound-properties>
	</munit:set>
	<!--Pass the payload into the flow to be unit-tested-->
	<flow-ref name="munit-demo-flow"/>
		
	<!-- Assert the flow behaved as designed for an invalid payload -->
	<munit:assert-on-equals expected-ref="#[400]" value-ref="#[payload.getStatusCode()]"/>
</munit:test>
<!--End of Second Test-->

The application would have failed during the build phase and would never have been deployed to production, as illustrated in the screenshot below.  Note that maven displayed how many tests were, how many failed, and the reasons of the failures:

Note that the unit tests covered both the “happy path” and the “sad path” to achieve sufficient code coverage. If the code covered by the unit tests were sparse, erroneous lines could still slip in and remain undetected.

Hopefully this explains the title of this blog entry and it all makes sense now. If not, WTF is the most used abbreviation in the tech industry anyway, and the best part about WTF is that you can sprinkle it all over your code comments, and no amount of automated unit testing will ever catch it.


We'd love to hear your opinion on this post


5 Responses to “Man in the Mirror, Apple’s Security Flaw, and the Importance of Unit Testing”

  1. Haha,, loved this post!

  2. Hi, i am new to Mule and am having trouble running this example. I imported the project in Studio using the pom.xml

    The first error is

    Unable to find artifact. Failure to find com.cloveretl:cloveretl-engine:zip:3.4.2

    Also, i have several jar files that have errors.

    Any help would be appreciated.

    thanks

    • Are you using our EE edition, specifically, 3.4.2 release? Also, can you reach the necessary maven repos from your environment? CloverETL is part of our DataMapper feature. The error you are describing, seems to imply you’re using an older version of our Studio?

    • Also you should go here to download MUnit and install it locally into your local maven repo: https://github.com/mulesoft/munit/ Please pick the right branch for the Mule version you’re using. Thanks.

  3. Adrian, great post!

    I ran into a dependency issue finding current Mule Interceptor Module when running this from the command line, using Maven “mvn clean install”.

    To resolve the dependency issue I modified the pom.xml as follows:

    195c195
    <

    >
    198c198,216
    < ${munit.version}

    > ${munit.version}
    >
    >
    > org.mule.munit.tools
    > munit-maven-plugin
    > ${munit.version}
    >
    >
    > org.mule.modules
    > mule-interceptor-module
    >
    >
    >
    >
    > org.mule.modules
    > mule-interceptor-module
    > LATEST
    >
    >
    399a418,422
    >
    > org.mule.modules
    > mule-interceptor-module
    > LATEST
    >

    This essentially removes the unresolvable dependency baked within Munit and adds in a dependency attempting to find the Latest version available for the module in question.

    Depending upon your Mule Mix, you may need to adjust per dependency versions.

    Hope this helps someone!

    Thanks,
    Jeff