Integrating TouchID with Authorization Services

I'm currently using authorization services in a factored app(user mode app + privileged helper tool). When performing a privilged operation, the user is prompted for their password. How can I also allow authentication through touch ID?


Additional info:

Device: MacBook Pro (15-inch, 2017)

macOS version: 10.13.4 (17E202)


The code is adapted from the EvenBetterAuthorizationSample, so nothing fancy going on there.

I also dug around a bit through /usr/libexec/authopen which does allow the user to choose between TouchID and password. If use codesign to change it's signature, only the password prompt is shown. Am I correct to assume that this feature is currently available only for Apple signed applications/binaries?


As an alternative, I also fiddled around with LocalAuthentication which works great for a standalone app, but does it provide a way of passing the context between processes, as with AuthorizationMakeExternalForm?

Accepted Reply

Am I correct to assume that this feature is currently available only for Apple signed applications/binaries?

I had a quick look at this and, as far as I can tell, that does seem to be the case [1]. However, I may be missing something here. If you’d like someone to dig into this in more detail, you should open a DTS tech support incident for it (with the caveat that the final answer may well be “file an enhancement request”).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] If you look in the Darwin source you’ll see that the authorisation engine sets

AGENT_HINT_CLIENT_FROM_APPLE
and it seems that the SecurityAgent keys off that.

Replies

Am I correct to assume that this feature is currently available only for Apple signed applications/binaries?

I had a quick look at this and, as far as I can tell, that does seem to be the case [1]. However, I may be missing something here. If you’d like someone to dig into this in more detail, you should open a DTS tech support incident for it (with the caveat that the final answer may well be “file an enhancement request”).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] If you look in the Darwin source you’ll see that the authorisation engine sets

AGENT_HINT_CLIENT_FROM_APPLE
and it seems that the SecurityAgent keys off that.

I recently had cause to revisit this as part of a DTS incident. To start, I set up a test by creating an app that calls

AuthorizationCopyRights
to get the
system.privilege.admin
right. I then compared that UI to the UI presented by the following AppleScript, which internally requests the same right:
do shell script "true" with administrator privileges

These look very different. My app presents a user/password dialog, whereas the AppleScript presents a Touch ID dialog, with a Use Password button that leads to the same user/password dialog presented by my app.

So, we have two different apps that both request the same right, but one allows Touch ID and the other doesn’t. Why?

The answer is that the system authorisation plug-in that handles these requests [1] has a hard-coded check for Apple-signed code. If the requesting process’s main executable is signed by Apple, it allows the use of Touch ID. If not, it skips that option and always prompts for a password.

               *                   *                   *

I also researched the possibility of installing a custom authorisation plug-in that uses the LocalAuthentication framework to authenticate the user, and then customising my authorisation rights to use that authorisation plug-in. However, this will not work. In talking with the LocalAuthentication team, they made it very clear that this API was designed for use by apps and it is not supported in non-app contexts, like from an authorisation plug-in.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
(s. 732256176)

[1] The

system.privilege.admin
right uses a
class
>
user
rule:
% security authorizationdb read system.privilege.admin

That redirects the authentication to the

authenticate
right:
% security authorizationdb read authenticate

That authenticates the user via the

builtin:authenticate
mechanism. It’s this mechanism that contains the hard-coded check for Apple-signed code.

I have similar problem. Original post was several years ago. Is there any new features/API to retrieve AuthorizationRef by TouchID?

Is there any new features/API to retrieve AuthorizationRef by Touch ID?

No.

Although ping this thread after WWDC and we’ll talk again then.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

At Apple Labs engineer told me to use LAContext ( LocalAuthentication.framework ), because this object is adopting NSSecureCoding protocol and can be used to authenticate user.

The flow is simple.

  1. Create LAContext at main GUI.
  2. Authenticate user via canEvaluatePolicy() and evaluatePolicy()
  3. Send LAContext through XPC to your desired service.
  4. Call canEvaluatePolicy() and evaluatePolicy() again.

However, I have a problem with last part. I made a wrapper object which carries LAContext through XPC. ( AuthorizationPayload ). It works fine and carries LAContext to service from main GUI.

However, when I try to verify LAContext on service side, I receive errors:

LAContext[61791:0] failed to initialize: Error Domain=com.apple.LocalAuthentication Code=-10 "Context not found." UserInfo={NSDebugDescription=Context not found., NSLocalizedDescription=Authentication failure.}

and

canEvaluatePolicy() also returns false with the same error.

Additional. I also added this sandbox rule to my service.

(allow mach-lookup (global-name "com.apple.CoreAuthentication.daemon") )

What can I do in this situation?

Send LAContext through XPC to your desired service.

Is this an XPC service? That is, a bundle with the extension .xpc that’s packaged within your app?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

We distribute our product outside of the MAS (as a pkg).

It consists of GUI app and several services.

App is sandboxed but it uses custom sandbox profile rules.

Services are installed as launchd daemons and are not located inside the app bundle.

Services have xpc bundles and also use custom sandbox profiles.

Services are installed as launchd daemons

So you’re trying to archive the LAContext in your app and then unarchive and use it in your launchd daemon? If so, that’s not going to work. There are actually two different problems:

  • Local Authentication is intended to be used from a user login context, not from the global context in which launchd daemons run.

  • The launchd daemon and the app run in different security contexts, and you can’t move Local Authentication contexts between security contexts.

For more background on how macOS structures execution contexts, see the Execution Contexts section of Technote 2083 Daemons and Agents.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"