Structure and Interpretation of Computer Programmers

I make it easier and faster for you to write high-quality software.

Friday, January 29, 2010

It’s just a big iPod

I think you would assume I had my privacy settings ramped up a little too high if I hadn’t heard about the iPad, Apple’s new touchscreen mobile device. Having had a few days to consider it and allow the hype to die down, my considered opinion on the iPad’s security profile is this: it’s just a big iPod.

Now that’s no bad thing. We’ve seen from the iPhone that the moderated gateway for distributing software—the App Store—keeps malware away from the platform. Both the Rickrolling iKee worm and its malicious sibling, Duh, rely on users enabling software not sanctioned through the app store. Now whether or not Apple’s review process is a 100% foolproof way of keeping malware off iPhones, iPods and iPads is not proven either way, but it certainly seems to be doing its job so far.

Of course, reviewing every one of those 140,000+ apps is not a free process. Last year, Apple were saying 98% of apps are reviewed in 7 days, this month only 90% are approved in 14 days. So there’s clearly a scalability problem with the review process, and if the iPad does genuinely lead to a “second app store gold rush” then we’ll probably not see an improvement there, either. Now, if an app developer discovers a vulnerability in their app (or worse, if a zero-day is uncovered), it could take a couple of weeks to get a security fix out to customers. How should the developer deal with that situation? Should Apple get involved (and if they do, couldn’t they have used that time to approve the update)? Update: I’m told (thanks @Reversity) that it’s possible to expedite reviews by emailing Apple. We just have to hope that not all developers find out about that, or they’ll all try it.

The part of the “big iPod” picture that I find most interesting from a security perspective, however, is the user account model. In a nutshell, there isn’t one. Just like an iPhone or iPod, it is assumed that the person touching the screen is the person who owns the data on the iPad. There are numerous situations in which that is a reasonable assumption. My iPhone, for instance, spends most of its time in my pocket or in my hand, so it’s rare that someone else gets to use it. If someone casually tries to borrow or steal the phone, the PIN lock should be sufficient to keep them from gaining access. However, as it’s the 3G model rather than the newer 3GS, it lacks filesystem encryption, so a knowledgeable thief could still get the data from it. (As an aside, Apple have not mentioned whether the iPad features the same encryption as the iPhone 3GS, so it would be safest to assume that it does not).

The iPad makes sense as a single-user or shared device if it is used as a living room media unit. My girlfriend and I are happy to share music, photos, and videos, so if that’s all the iPad had it wouldn’t matter if we both used the same one. But for some other use cases even we need to keep secrets from each other—we both work with confidential data so can’t share all of our files. With a laptop, we can each use separate accounts, so when one of us logs in we have access to our own files but not to the other’s.

That multi-user capability—even more important in corporate environments—doesn’t exist in the iPhone OS, and therefore doesn’t exist on the iPad. If two different people want to use an iPad to work with confidential information, they don’t need different accounts; they need different iPads. [Another aside: even if all the data is “in the cloud” the fact that two users on one iPad would share a keychain could mean that they have access to each others’ accounts anyway.] Each would need to protect his iPad from access by anyone else. Now even though in practice many companies do have a “one user, one laptop” correlation, they still rely on a centralised directory service to configure the user accounts, and therefore the security settings including access to private data.

Now the iPhone Configuration Utility (assuming its use is extended to iPads) allows configuration of the security settings on the device such as they are, but you can’t just give Jenkins an iPad, have him tell it that he’s Jenkins, then have it notice that it’s Jenkins’s iPad and should grab Jenkins’s account settings. You can do that with Macs and PCs on a network with a directory service; the individual computers can be treated to varying extents as pieces of furniture which only become “Jenkins’s computer” when Jenkins is using one.

If the iPad works in the same way as an iPhone, it will grab that personal and account info from whatever Mac or PC it’s synced to. Plug it in to a different computer, and that one can sync it, merging or replacing the information on the device. This makes registration fairly easy (“here’s your iPad, Jenkins, plug it in to your computer when you’re logged in”) and deregistration more involved (“Jenkins has quit, we need to recover or remove his PIN, take the data from the iPad, then wipe it before we can give it to Hopkins, his replacement”). I happen to believe that many IT departments could, with a “one iPad<->one computer<->one user” system, manage iPads in that way. But it would require a bit of a change from the way they currently run their networks and IT departments don’t change things without good reason. They would probably want full-device encryption (status: unknown) and to lock syncing to a single system (status: the iPhone Enterprise Deployment Guide doesn’t make it clear, but I think it isn’t possible).

What is clear based on the blogosphere/twitterverse reaction to the device is that many companies will be forced, sooner or later, to support iPads, just as when people started turning up to the helpdesks with BlackBerries and iPhones expecting them to be supported. Being part of that updated IT universe will make for an exciting couple of years.

posted by Graham at 06:03  

Sunday, January 10, 2010

Unit testing Core Data-driven apps, fit the second

It took longer than I expected to follow up my previous article on unit testing and Core Data, but here it is.

Note that the pattern presented last time, Remove the Core Data Dependence, is by far my preferred option. If a part of your code doesn’t really depend on managed objects and suchlike, it shouldn’t need them to be present just because it works with (or in) classes that do. The following pattern is recommended only when you aren’t able to abstract away the Core Data-ness of the code under test.

Pattern 2: construct an in-memory Core Data stack. The unit test classes you develop ought to have these, seemingly contradictory properties:

  • no dependence on external state: the tests must run the same way every time they run. That means that the environment for each test must be controlled exactly; dependence on “live” application support files, document files or the user defaults are all no-nos.
  • close approximation to the application environment: you’re interested in how your app runs, not how nice a unit test suite you can create.

To satisfy both of these properties simultaneously, construct a Core Data stack in the test suite which behaves in the same way but which does not use the persistent store (i.e. document files) used by the real app. My preference is to use the in-memory store type, so that every time it is created it is guaranteed to have no reference to any prior state (unlike a file-backed store type, where you have to rely on unlinking the document files and hoping there are no timing issues in the test framework which might cause two tests simultaneously to use the same file).

My test case class interface looks like this (note that this is for a dependent test case bundle that gets embedded into the app; there’s an important reason for that which I’ll come to later). The managed object context will be needed in the test methods to insert new objects, I don’t (yet) need any of the other objects to be visible inside the tests but the same objects must be used in -setUp and -tearDown.

#import <SenTestingKit/SenTestingKit.h>

@interface SomeCoreDataTests : SenTestCase {
NSPersistentStoreCoordinator *coord;
NSManagedObjectContext *ctx;
NSManagedObjectModel *model;
NSPersistentStore *store;
}

@end

The environment for the tests is configured thus. I would have all of the error reporting done in tests, rather than that one lone assertion in -tearDown, because the SenTest framework doesn’t report properly on assertion failures in that method or in -setUp. So the -testThatEnvironmentWorks test method is a bellwether for the test environment being properly set up, but obviously can’t test the results of tear-down because the environment hasn’t been torn down when it runs.


#import "TuneNeedsHighlightingTests.h"

@implementation TuneNeedsHighlightingTests

- (void)setUp
{
model = [[NSManagedObjectModel mergedModelFromBundles: nil] retain];
NSLog(@"model: %@", model);
coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: model];
store = [coord addPersistentStoreWithType: NSInMemoryStoreType
configuration: nil
URL: nil
options: nil
error: NULL];
ctx = [[NSManagedObjectContext alloc] init];
[ctx setPersistentStoreCoordinator: coord];
}

- (void)tearDown
{
[ctx release];
ctx = nil;
NSError *error = nil;
STAssertTrue([coord removePersistentStore: store error: &error],
@"couldn't remove persistent store: %@", error);
store = nil;
[coord release];
coord = nil;
[model release];
model = nil;
}

- (void)testThatEnvironmentWorks
{
STAssertNotNil(store, @"no persistent store");
}
@end

The important part is in setting up the managed object model. In using [NSManagedObjectModel mergedModelFromBundles: nil], we get the managed object model derived from loading all MOMs in the main bundle—remembering that this is an injected test framework, that’s the application bundle. In other words the MOM is the same as that created by the app delegate. We get to use the in-memory store as a clean slate every time through, but otherwise the entity definitions and behaviours ought to be identical to those provided by the real app.

posted by Graham Lee at 18:12  

Friday, January 1, 2010

CocoaHeads Swindon, January and February

The next CocoaHeads Swindon will take place on 4th January, at the Glue Pot in Swindon. Get here at 8 for some NSChitChat with your (well, my) local Mac developer community.

There is no February meeting of Swindon CocoaHeads, on account of NSConference Europe taking place in Reading on that weekend. So buy your NSConference ticket and come along to say hi!

posted by Graham Lee at 14:15  

Powered by WordPress