Today @nathanharper and I paired on the development of the interexchange/campminder-rb gem. Our primary goal was to understand how the authentication and encryption sections of their API operates. We're still waiting on access to a staging environment, but in the mean time we'd been blessed with a C Sharp implementation of the same system we needed to build.
Having neither of us worked in C Sharp before…
The morning started with analysis of the current codebase, for about 3 minutes we attempted to get the project working on my laptop. We ended up catching Mono, which isn't as bad as you think it is, but still not great, and highly ineffective. We realized that reading the code would probably suffice for building our implementation.
We made the decision that we don't know anything more than what we see in the code, we can safely assume that this is going to result in an implementation that will correlate with the other system.
This may not be our final implementation, we're going to work iteratively and use tests to guide out what should be similar solutions to the original implementation.
We read through it, we groked it, tl;dr; we needed to take in a form post, check the signature of an encoded attribute, authenticate the username and password in our system, and redirect the user with a success/failure.
Enter a Test
So we wanted a ClientLinkRequest to initialize, and response to being valid? Testing we first we just expect the object to exist, and for the valid? method to return false.
So yes, we're going to eventually be dealing with HTTP requests and forms with parameters, but these things were problems we know how to solve, we needed to enter the unknown first so we could gauge the complexity of this problem.
What was it that determined whether this ClientLinkRequest was valid?, we looked at the current implementation and read through the docs, there was an attribute coming through from the form post called signedObject, the payload of which was a DateTime object at UTC.
Before getting there though we were going to have decrypt and verify the payload.
This called for a SignedRequestFactory which could do all the work to get_payload.
I really wasn't sure about testing the private method, I kind of wanted to just affirm that, yes the class is initialized with the SECRET_CODE, but it's not meant to be accessible beyond there.
Honestly implementing it with virtus was really nice, kind of played to my how-i-feel-about-static-types-these-days, man programming gets more interesting every day that you do it. Anyway this is simple, if just for its verbosity.
Testing The Interface
So we have a ClientLinkRequest which will tell us if the authorization attempt is valid, based on the SignedRequestFactory authorizing the signedObject. What we needed to do now was tie this into the params coming into one of our controllers.
To test this we wanted to come from the top down and create an API test that would ensure a valid request resulted in a redirect to the success URL, for this we would use Rack::Test.
This would mean we needed a web server in our test environment. I could have done this test first, but knowing this would be a requirement I decided to leave it until after the logic had been figured.
Here's how we did it spec/ $ rails new dummy # --flags?.
We pruned things up, got rid of assets etc, flags would have been more efficient, here's the commit
The end result is still a bit messy, but gets the success and failure results specced out, a good first day.