square / Valet

Valet lets you securely store data in the iOS, tvOS, or macOS Keychain without knowing a thing about how the Keychain works. It’s easy. We promise.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Reading only works immediately AFTER a write?

ehlersd opened this issue · comments

I'm sure I'm doing something wrong....

I bring up my Login screen and load the username/password from the SecureEnclaveVault. The reads ALWAYS fail with ItemNotFound errors.

The user enters their username/password, hits Login...it logs in then I save the Username/Password into the SecureEnclaveVault and immediately try to read them back. Doing so triggers the Face/TouchID and after correctly reads the values.

That screen automatically closes. I then Logout and try to Login again, and the entire thing is repeated....including the reading of Username/Password failing.

I've tried this on the Simulator (iOS13.5) with TouchID enrolled, as well as on my physical iPhone XS running iOS14. This is using the latest Valet 4.1.1.

Any help as to what I'm missing here?

Hi @ehlersd! Thanks for the report. This is a new one, and off the top of my head I'm not sure what's wrong. I appreciate that you've tried both a simulator and a physical device – that helps rule out some possibilities.

I'm able to get a SecureEnclaveValet working as part of our TouchID test target, so I know this can work.

I'm happy to help you debug, but I'm going to need more info since I can't reproduce locally: can you create a sample project or snippet which reproduces the error? Getting a sample attached to this Issue would enable me to help you.

I'm also curious: do you see the same unexpected behavior if you use a regular Valet – one that doesn't require biometrics to unlock?

I'll switch the valet type and see how it functions.

Additionally, getting a sample project may take some doing, as this is part of a fairly large commercial app I'm working on for a client.

Here's the code I'm using, let me know if you see anything weird here. If you don't see anything and none-biometric valet test works fine, then I'll start down the road of putting together a sample project.

//
//  WKRSecureEnclaveCacheWorker.swift
//  Main Event Prototype App
//
//  Created by Darren Ehlers on 2019/12/06.
//  Copyright © 2019 Main Event Entertainment, LP. All rights reserved.
//

import Foundation
import DNSBlankWorkers
import DNSProtocols
import Valet

open class WKRSecureEnclaveCacheWorker: WKRBlankCacheWorker
{
    private lazy var myValet: SecureEnclaveValet = {
        let valet = SecureEnclaveValet.valet(with: Identifier(nonEmpty: MEEAppConstants.Biometrics.valet)!,
                                             accessControl: .userPresence)
        return valet
    }()

    // MARK: - Business Logic / Single Item CRUD

    override open func doDeleteObject(for id: String,
                                      with progress: PTCLProgressBlock?,
                                      and block: PTCLCacheBlockVoidDNSError?) throws {
        do {
            try myValet.removeObject(forKey: id)
        } catch {
            // TODO: Needs Error
            block?(nil)
            return
        }

        block?(nil)
    }

    override open func doReadObject(for id: String,
                                    with progress: PTCLProgressBlock?,
                                    and block: PTCLCacheBlockVoidAnyDNSError?) throws {
        var retval: Any
        do {
            retval = try myValet.object(forKey: id,
                                        withPrompt: MEESignInStage.Localizations.Biometric.prompt)
        } catch {
            // TODO: Needs Error
            block?(nil, nil)
            return
        }

        block?(retval, nil)
    }

    override open func doLoadImage(from url: NSURL,
                                   for id: String,
                                   with progress: PTCLProgressBlock?,
                                   and block: PTCLCacheBlockVoidAnyDNSError?) throws {
        // TODO: Needs Error
        block?(nil, nil)
    }

    override open func doUpdate(object: Any,
                                for id: String,
                                with progress: PTCLProgressBlock?,
                                and block: PTCLCacheBlockVoidAnyDNSError?) throws {
        if object as? String != nil {
            do {
                // swiftlint:disable:next force_cast
                try myValet.setString(object as! String,
                                      forKey: id)
            } catch {
                // TODO: Needs Error
                block?(nil, nil)
                return
            }

            block?(object, nil)
            return
        }

        if object as? Data != nil {
            do {
                // swiftlint:disable:next force_cast
                try myValet.setObject(object as! Data,
                                      forKey: id)
            } catch {
                // TODO: Needs Error
                block?(nil, nil)
                return
            }

            block?(object, nil)
            return
        }

        // TODO: Needs Error
        block?(nil, nil)
    }
}

I changed the valet creation to:

    private lazy var myValet: Valet = {
        let valet = Valet.valet(with: Identifier(nonEmpty: "WKRKeychainCacheWorker")!,
                                accessibility: .whenUnlocked)
        return valet
    }()

And got the same results exactly...with zero persistence. Looks like the biometrics has nothing to do with it.

Interesting! There is no obvious misuse of Valet in that code sample.

At this point, I'm curious if your IDs you're using to query Valet are changing from underneath you, or if you have some other code that is causing the keychain to be cleared or modified when your screen is dismissed.

Hmmm....I don't think so, but let me dig further into my Okta sign out code. I'll let you know.

Found the issue! When doing the Okta SDK session clear call, it actually is clearing everything from the Keychain, instead of just it's items.... It appears to be working well now!

Great! I'll close this issue out.