adding a new security right

I'm trying to add a new right 'com.mycompany.dosomething' so that AuthorizationCopyRights can ask for the current user to verify possession of the right. I found the 'security authorizationdb write' command, and have been working toward reverse-engineering a right's .plist specification. Is there a spec someplace that actually documents what goes in a right?


The 'class' and 'allow-root' keys seem the most puzzling, just from what I've seen in existing rights. But what I'd really like is a list of the supported keys and what their settings mean.

Replies

Is there a spec someplace that actually documents what goes in a right?

No, alas. This has been a long-standing complaint about Authorization Services from day one. I’m pretty sure we already have a bug on file about this but you should feel free to file your own, so you can explain how this is inconveniencing you in your own words.

Please post your bug number, just for the record.

Note Some of the keys are documented in

<Security/AuthorizationDB.h>
but this is nowhere near sufficient.

The

class
and
allow-root
keys seem the most puzzling …
class
is the main control point in the right specification. You can expect to see values like:
  • user
    , which indicates that the right is obtained by satisfying user requirements (for example,
    group
    indicates that the user must be a member of the specified group)
  • rule
    , which indicates that the right indirectly references one or more rules
  • evaluate-mechanisms
    , which indicates that the right can only be obtained if all of the mechanisms in the
    mechanisms
    array are run successfully

    Note mechanisms are exposed by authorisation plug-ins, which is a whole other topic entirely.

  • allow
    , which indicates that the right is always allowed
  • deny
    , which indicates that the right is never allowed
allow-root
is for
user
class rights and indicates that a root process can satisfy the right without further authentication.

In the absence of proper documentation my recommendation is that you look through the existing rights in the authorization database to see how they’re specified. This is tricky to do because

security authorizationdb
doesn’t let you list out the rights (that’s also bugworthy IMO). I worked around this by dumping the rights using
sqlite
:
$ echo "select name from rules;" | sudo sqlite3 /var/db/auth.db > right-names.txt

WARNING The above is for debugging purposes only. The location and format of the authorisation database is not considered API. It has changed in the past and may well change again in the future.

You can then take that output and call

security authorizationdb
on each item:
$ for i in `cat right-names.txt`; do echo "--- right '$i' ---" >> right-specifications.txt ; security authorizationdb read $i >> right-specifications.txt ; done

Finally, if you get really stuck you can take a look at

AuthorizationTagsPriv.h
in Darwin.

WARNING You have to be careful when looking at Darwin source because it’s a specification of the implementation, not of the API. In this case I think it’s reasonable to look at the comments in this file to understand the intended behaviour of authorisation database keys, but you have to be careful to avoid binding your app so tightly to the implementation that it breaks when the implementation changes.

Share and Enjoy

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

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

Using sqlite to find the names of existing rules, 'security authorizationdb read' to get their plist settings, and copying from there - that all works well enough. Thanks in particular for explaining 'class'.


I'm still having a lot of trouble getting AuthorizationCopyRights to put up the username/password dialog box. It works fine if I run from Xcode, or from the command line, or from Launchpad. But running from launchd causes CopyRights to return errAuthorizationInteractionNotAllowed. Yes, I'm including the relevant flag:

let authFlags:AuthorizationFlags = [ .interactionAllowed, .extendRights ]


The app is a LaunchAgent (not a LaunchDaemon) written in Swift, that otherwise runs its UI just fine. Bonus: I put in an NSAlert box, and my UI now correctly reports SecurityManager's inability to connect to the UI.

The app is a LaunchAgent …

Have you set

LimitLoadToSessionType
property to just
Aqua
in your launchd property list file? Without that your agent can be loaded in session that does not have access to the window server.

Also, while you’re debugging you’ll need to ensure that your agent is loaded in the right context. How you do this depends on how you’re loading your agent:

  • If you’re using the new

    launchctl
    commands (
    bootstrap
    and
    bootout
    ) you must specify a
    gui/<uid>
    domain target.
  • If you’re using the legacy

    launchctl
    commands (
    load
    and
    unload
    ) you must supply the
    -S Aqua
    option.

Share and Enjoy

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

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

The bits about Aqua were great. And obscure... So while my auth sequence is doing pretty well, there's a new stumper. When AuthorizationCopyRights puts up the username/password dialog, it usually has no text in the OK button. Just blank blue. For fun, it occasionally does show "OK" as it should.


I'm using a plist loaded in a shell script, through 'security authorizationdb write'. Found an example on some message board that used default-button and default-prompt keys, but I haven't gotten them to do anything. There's code in TN2095 that uses AuthorizationRightSet that I haven't yet tried to ingest, if that would be different.


The Cancel button displays correctly even when clicked on, so I'm thinking it's not a blue-on-blue display thing. And if was some horrible localization failure, or an artifact of how the dialog is invoked, wouldn't that kill Cancel in the same way?


Similarly, I can't change the caption. It just says "<application name> wants to make changes." Which is okay, but it does feel related. So, how is one supposed to control the password UI?

When

AuthorizationCopyRights
puts up the username/password dialog, it usually has no text in the OK button.

Well, that’s weird. I’ve never seen that before.

So, how is one supposed to control the password UI?

There’s very limited control over this UI, something that’s not accidental but rather a deliberate design choice.

default-prompt
is one of the few knobs, so I recommend that you check that out; it worked the last time I tested it, that is, back when I wrote TN2095 (-:

I don’t think we ever formally documented

default-button
but that’s not saying much given the poor overall documentation of this data structure.

Share and Enjoy

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

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

I did find lines like this in authd.log:

Failed to authorize right '@2^H' by client


I think somewhere it doesn't know the name of my right. And while the authorization itself seems to be fine, maybe this log line is a symptom of the same thing that interferes with the UI. Can you identify where the data comes from that the log line expects?


The one place I do supply the name of the right is in an AuthorizationItem that's in the AuthorizationRights object I send to AuthorizationCopyRights.


and fyi, https://bugreport.apple.com/web/?problemID=34756874

Failed to authorize right '@2^H' by client

Well, that’s bogus.

Can you identify where the data comes from that the log line expects?

On what version of macOS did you see that log message?

Share and Enjoy

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

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

So that was all on ElCapitan. Bogus, yes.


Funny that you should ask about version - this weekend I moved from ElCapitan to HighSierra, and from XCode8 to XCode9. Everything's different. To begin with, authd.log is gone. Console doesn't show it either. Where did the logs go?


And my blue-button draw problem is gone - works fine now. Except now the first trip through AuthorizationCreate returns errAuthorizationInternal where it used to work fine. So now I'm working on retry strategies. At this point the process of getting a simple app to authenticate has taken me a day or so in the code, and more like ten days in StackOverflow and Google looking for lore.

Where did the logs go?

There was a major update to our platform logging with iOS 10 and friends. WWDC 2016 Session 721 Unified Logging and Activity Tracing has the details. In most cases logging hasn’t been removed, but lots of stuff got shuffled around.

With regards

authd.log
specifically, I’ve never used that log before (I suspect it was introduced after I last did any serious work with Authorization Services) so I’ve never had a need to go looking for it on modern systems. But hey, there’s a first time for everything.

Here’s what I did:

  1. I fired up my 10.11.6 VM and ran my standard test (which is to invoke Fast User Switching to switch to a different user, then enter the wrong password, then cancel it). In

    /var/log/authd.log
    I see a new line like this:
    Oct  4 01:06:02 Virtual-Cap authd[108]: Failed to authorize right 'system.login.fus' by client '/System/Library/CoreServices/loginwindow.app' [238] for authorization created by '/System/Library/CoreServices/loginwindow.app' [238] (3,0) (-60006)

    -

  2. I fired up my 10.13 VM.

  3. I launched Console.

  4. I enabled Action > Include Info Messages and Action > Include Debug Messages.

  5. I started a search for “Failed to authorize right”.

  6. I repeated my standard test.

  7. On coming back to my original user, I saw the following log entry in Console:

    default
    01:10:12.053234 -0700
    authd
    Failed to authorize right 'system.login.fus' by client '/System/Library/CoreServices/loginwindow.app' [480] for authorization created by '/System/Library/CoreServices/loginwindow.app' [480] (3,0) (-60006)

    -

Once you get one log message like this, you can control click on it to work out the subsystem, category, and so on. In this case the subsystem is

com.apple.Authorization
, which makes a really good search filter.

Console lets you save search filters like this, so you can write it now and come back to it whenever you need it. And if you Console isn’t your thing, you can do similar things using the

log
command line tool.

Share and Enjoy

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

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

We have written succesfully an authorization plugin called GMIAuthPlugin. This plugin works very well on the initial login. We allow for an out of band 2 factor authorization at the login screen. We even allow for passwordless login today. Our next goal is to display this auth plugin when waking from the screen saver or locking the machine. We have tried the following plist to system.login.screensaver. This gets us close but not all the way. In doing some reading it has been stated that we need to use the older login rule <string>authenticate-session-owner-or-admin</string> instead of the newer rule use-login-window-ui. I have not been able to configure both a mechanism and a login rule in the system.login.screensaver successfully. I am sure this is possible and maybe I am missing something obvious. Using the command Security authorizationdb write system.login.screensaver authenticate-session-owner-or-admin overwrites the whole plist file and does not keep the mechanism part we want.



I have read this:

https://forums.developer.apple.com/thread/86537


And this thread:

https://forums.developer.apple.com/thread/110667


Here is our current system.login.screensaver plist. This displays our auth plugin. Our end goal is to send an out of band mobile message to our platform which will then unlock and login without manually typing the user’s password which we save and present for authorization.




<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>allow-root</key>

<false/>

<key>authenticate-user</key>

<true/>

<key>class</key>

<string>user</string>

<key>created</key>

<real>592759977.27845001</real>

<key>group</key>

<string>admin</string>

<key>mechanisms</key>

<array>

<string>GMIAuthPlugin:invoke</string>

<string>builtin:authenticate,privileged</string>

<string>builtin:auto-login,privileged</string>

<string>builtin:forward-login,privileged</string>

<string>PKINITMechanism:auth,privileged</string>

</array>

<key>modified</key>

<real>601410763.90900505</real>

<key>session-owner</key>

<true/>

<key>shared</key>

<false/>

<key>timeout</key>

<integer>2147483647</integer>

<key>tries</key>

<integer>10000</integer>

<key>version</key>

<integer>0</integer>

<key>class</key>

<string>rule</string>

<key>created</key>

<real>472414282.07143301</real>

<key>modified</key>

<real>498674468.80855602</real>

<key>version</key>

<integer>0</integer> </dict> </plist>

</dict>

</plist>


Thank you so much for your help on this!

Matt

@matt
Code Block
We have written succesfully an authorization plugin called GMIAuthPlugin. This plugin works very well on the initial login. We allow for an out of band 2 factor authorization at the login screen. We even allow for passwordless login today.

We are interested in knowing how passwordless login works at initial login, since builtin:authenticate which validates the login credentials. Could you please tell us how this can be achieved.
Any help in this request will be greatly appreciated.

Thanks you!!