Use Your Loaf

[[brain engage] write]

UYLPasswordManager Clearing the Cache

I recently posted a series of articles on the iOS keychain migration and data protection classes. I introduced the UYLPasswordManager class to experiment with some of the options but there was in hindsight one feature I left out of the class.

Clearing the cache

As I explained in the first post in the series on the keychain data protection classes by default new data added to the keychain is prevented from being accessed when the device is locked. You can change this behaviour if you want to allow the data to always be accessible but Apple recommends you choose the most restrictive class unless you have a reason to do otherwise. Setting this restriction on the keychain item is however pointless if you retrieve the keychain item and store it in an object somewhere in your application code for access when the device is locked.

The correct approach, assuming you do not need the keychain data when the device is locked, is to detect when the device is locked and clean up any keychain data you may be hanging onto. The UIApplication delegate provides a notification indicating when the device is about to be locked. In the example application that I used to demonstrate the UYLPasswordManager class I had the application delegate listen for this notification and then tell the UYLPasswordManager instance to purge the cached keychain data. A similar approach is used to purge the data when the app moves to the background. However, in hindsight, it seems better to move this code into the UYLPasswordManager class itself.

Adding observers for the notifications

To have the UYLPasswordManager object detect when the application moves to the background or when the device is locked we need to listen for two notifications:

+ UIApplicationDidEnterBackgroundNotification
+ UIApplicationProtectedDataWillBecomeUnavailable

To ensure we always receive these notifications I add observers in the init method of the class as follows:

- (id)init {
  self = [super init];
  if (self) {
    _migrate = YES;
     _accessMode = UYLPMAccessibleWhenUnlocked;
    [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(deviceWillLockOrBackground:)
      name:UIApplicationProtectedDataWillBecomeUnavailable
      object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(deviceWillLockOrBackground:)
      name:UIApplicationDidEnterBackgroundNotification
      object:nil];
  }
  return self;
}

In both cases the UYLPasswordManager object is the observer (self) and the method that will be called has the selector deviceWillLockOrBackground:. Note that since we have registered the object as an observer we need to ensure to remove it when the object is deallocated:

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
  ...
  [super dealloc];
}

The actual method that gets called when the notification is received is trivial in that it just uses the purge method of the UYLPasswordManager to clear the cached values:

- (void)deviceWillLockOrBackground:(NSNotification *)notification {
  [self purge];
}

The nice thing about moving this code into the class is that I now no longer need to remember to do this for every application I write that uses the UYLPasswordManager class.

Get it on Github

I have updated the code on my Github page here if you want to take a closer a look or download the updated version. I have also updated the example app to remove the now redundant code.

Comments