5

I have an iOS project.

I have extracted some authentication code today and moved it to it's own project.

This project supports macOS and iOS.

I have created a workspace that contains both the iOS project and the Auth project and I have added the auth .framework to my iOS project via the Frameworks, Libraries, and Embedded Content panel.

I can build and use my services. I have also setup a custom scheme CI_iOS that allows me to run the tests for these projects.

I have now added some integration tests to my auth module, so I can test my KeychainTokenStore class against the real Keychain.

These work when testing my module against macOS, however attempting to run them on the iOS simulator they all fall.

I can see when attempting to interact with the Keychain an error code is returned -34018 which I believe indicates errSecMissingEntitlement.

I have been reading a number of posts that seem to suggest I need to enable keychain sharing.

I cannot seem to make this work however.

My KeychainTokenStore looks like this


import Foundation


public protocol TokenStore {
  typealias DeleteCacheResult = Result<Void, Error>
  typealias DeleteCacheCompletion = (DeleteCacheResult) -> Void

  typealias InsertCacheResult = Result<Void, Error>
  typealias InsertCacheCompletion = (InsertCacheResult) -> Void

  typealias RetrieveCacheResult = Result<String?, Error>
  typealias RetrieveCacheCompletion = (RetrieveCacheResult) -> Void

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func insert(_ token: String, key: String, completion: @escaping InsertCacheCompletion)

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func delete(_ key: String, completion: @escaping DeleteCacheCompletion)

  /// The completion handler can be invoked in any thread.
  /// Clients are responsible for dispatching to the appropriate thread, if needed.
  func retrieve(_ key: String, completion: @escaping RetrieveCacheCompletion)
}


public final class KeychainTokenStore: TokenStore {

  public enum Error: Swift.Error {
    case saveFailed
  }

  public init() { }

  private lazy var queue = DispatchQueue(label: "KeychainTokenStore.queue", qos: .userInitiated, attributes: .concurrent)

  public func insert(_ token: String, key: String, completion: @escaping InsertCacheCompletion) {
    queue.async(flags: .barrier) {
      completion(Result {
        let query = [
          kSecClass: kSecClassGenericPassword,
          kSecAttrAccount: key,
          kSecValueData: Data(token.utf8)
          ] as CFDictionary

        SecItemDelete(query)

        guard SecItemAdd(query, nil) == noErr else { throw Error.saveFailed }
      })
    }
  }

  public func delete(_ key: String, completion: @escaping DeleteCacheCompletion) {
    queue.async(flags: .barrier) {
      completion(Result {
        let query = [
          kSecClass: kSecClassGenericPassword,
          kSecAttrAccount: key,
          ] as CFDictionary

        SecItemDelete(query)
      })
    }
  }

  public func retrieve(_ key: String, completion: @escaping RetrieveCacheCompletion) {
    queue.async {
      let query = [
        kSecClass: kSecClassGenericPassword,
        kSecAttrAccount: key,
        kSecReturnData: kCFBooleanTrue as Any,
        kSecMatchLimit: kSecMatchLimitOne
        ] as CFDictionary

      var result: AnyObject?
      let status = SecItemCopyMatching(query, &result)

      guard status == noErr, let data = result as? Data else {
        return completion(.success(.none))
      }

      completion(Result {
        String(decoding: data, as: UTF8.self)
      })
    }
  }
}

In my iOS app I enabled sharing as follows:

sharing keychain

When I attempt to enable sharing in my auth framework however I see the following

error

How can I ensure my DigiAuth framework can access the Keychain with running my DigiApp project?

Harry Blue
  • 4,202
  • 10
  • 39
  • 78

1 Answers1

1

I ran into a similar issue and managed to fix it with this answer: https://stackoverflow.com/a/40587387/11316844

All you need to do is

  1. Add a new app target to your project
  2. Enable keychain sharing for this target
  3. Go to the test target of your project and set the Host application to the app you created in step 1
Esmee
  • 51
  • 8