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.