Antoine Bellanger

Developer, Designer, Quantum Physics lover.

Currently taking care of all Apple development at Biowatch. I'm also a WWDC17 and a RWDevCon 2018 Scholarship Recipient.

Follow me on Linkedin.

SFAuthorizationPluginView Introduction

Since a few months, I have had the chance to work with SFAuthorizationPluginView for macOS.

Sadly, documentation is lacking and understanding what this plugin does, how to install and test it and how not to destroy your computer is quite hard. Therefore, I wanted to make a blog post wrapping up all this as a guide for beginners and curious coders who want to experiment coding their own plugin.

Before we start :

A few useful links :

What you will need :

  • Two Mac (if you want to be safe)
  • An SSH connection between those two Mac
  • A little command-line knowledge
  • Time
  • A Time Machine backup of the Mac you will be testing the plugin on (just in case)
  • Not to be scared of really weird bugs crashing the login system (and eventually all your Mac).

Disclaimer: I advise you to carefully read all the blog post. I give a lot of informations and copying only the code will result in a failure or even worse as we are dealing with very fragile components. I personally had to delete everything I had on my Mac more than a few times because of weird bugs. You should also be comfortable with SSH, Shell scripts and command line.

Disclaimer #2: I made every attempt to ensure the accuracy and reliability of this blog post but code evolves so the information is provided "as is". I won't accept any responsibility or liability in case of problems with the code.

What is this "Plugin View" ?

The official definition of a SFAuthorizationPluginView says it:

"Allows authorization plug-in developers to create a custom view their plug-in can display." - Apple Developer

The definition is quite exhaustive so let's be a little bit more detailed and clear.

A SFAuthorizationPluginView allows you to create a custom UI component that will be displayed during the login process. It is useful if you want to let the user login with a system that you engineered.

For example, you could store the user's password inside the code and instead show a plugin asking the user to pick a color. If the color is right, log the user in (although I wouldn't try that).

Let's start

Apple used to have a demo project on their website but it seems they have removed it. It's not too bad as it was not working anymore. A user posted on Github a fixed version of the project so we will use this as our demo project.

You can clone it directly from Github.

The Code

I won't dive deep into the code but just a word on the main files.

AuthPlugin.h / AuthPlugin.m

This part of the code is responsible of the invoke mechanism that will be called from the loginwindow. It initialises the plugin view that is coded in the next part. There's not much to change and play with here for the demo.

If you want to have different mechanisms identifiers initializing different plugins or methods, you can do that from here.

NameAndPasswordPlugin.h / NameAndPasswordPlugin.m

Here you can create the links with your UI and handle all the authorization mechanisms. This is where you are going to be able to code whatever the login process you want to appear.

Installation & Testing

Plugin Installation

Obviously, you will need to build the project to start.

Then, there are a few things to do to install the plugin.

  1. Copy the bundle in the /SecurityAgentPlugins folder.
  2. Change the ownership to root.
  3. Set permissions to rwxr-xr-x.
1. Copy the bundle in the SecurityAgentPlugins folder.

Where can you find the bundle ?

Xcode stores all the builds in a folder named DerivedData. You can access it by typing into the Terminal :

cd ~/Library/Developer/Xcode/DerivedData/NameAndPassword-XXX/Build/Products/Debug

where XXX is a random sequence created by Xcode.

In this folder you should have the latest build of your NameAndPassword.bundle. You will need to copy it to /Library/Security/SecurityAgentPlugins. You can do that by using the cp command :

sudo cp -R NameAndPassword.bundle /Library/Security/SecurityAgentPlugins/

Note : Sometimes, for a weird reason I haven't find yet, this command wouldn't copy correctly the latest NameAndPassword.bundle to the folder. What I did as a workaround was to change the version number with something like 1.0.XXX everytime I created a new build so I could check if the latest version was in the /SecurityAgentPlugins folder (simply using the details showed in the Finder).

2. Change the ownership to root.

Simply type in this command :

sudo chown -R root:wheel /Library/Security/SecurityAgentPlugins/NameAndPassword.bundle

3. Set permissions to rwxr-xr-x (755).

Same, type in this command in your Terminal :

sudo chmod -R 755 /Library/Security/SecurityAgentPlugins/NameAndPassword.bundle

Now the plugin is installed where it should be, has the right permissions and ownership. Finally, we now need to update the security.login.console so that it loads our custom plugin.

Loading the plugin

Here we need to be very careful about the modifications we are changing a core part of the login system. My advice would be to double check every time all the parameters, if you want to avoid having to erase your hard drive and install a clean copy of macOS.

The security.login.console is a plist file that contains the mechanisms that are called when the loginwindow is showed.

First, let's save the current procedure, for this, you need to run :

security authorizationdb read system.login.console > system.login.console.original.txt

You will get a system.login.console.original.txt containing the current mechanisms. We are going to make a copy of this file so we keep the original as a backup in case we need to restore it.

cp system.login.console.original.txt system.login.console.custom.txt

Let's edit the custom file so that during login the system invokes the NameAndPassword plugin. Using your favorite text editor (vi, TextEdit...), you need to change the line loginwindow:login with NameAndPassword:invoke.

This means that instead of showing the classical loginwindow, it will instead load our custom plugin view.

Then, let's update the authorizationdb with our updated mechanisms :

sudo security authorizationdb write system.login.console < system.login.console.custom.txt

That's it, plugin is ready to use. You should now establish a SSH connection between your two Mac. You will be able to try and restore the login system from the other Mac in case the plugin is broken and crashes the login system.

SSH Connection

I will not introduce in detail what is SSH here but it is simply a protocol which allows you to communicate between your Mac using it.

SSH connection is useful when you test your SFAuthorizationPluginView because you can access the Terminal from your Mac which has the plugin installed from another Mac. Therefore, you can try saving it if something is broken with your plugin before being forced to reboot it.

On the Mac which has the plugin installed, go to Sharing in the System Preferences and there enable Remote Login. You should have a line saying "To log in to this computer remotely, type "ssh 'session'@'mac[or]ip'".

Just type in this command into the Terminal of your secondary Mac and follow the instructions. You should be asked about the authenticity of the fingerprint (say yes) and to type in the password to log into your Mac.

Then cd to the folder where are your security.login.console.txt files you saved earlier. The idea is that from the Mac which has no plugin, you can directly restore the old (and original) mechanisms file and reboot the login system.

And you're all set ! Now if you log out ( > Log Out) or switch users you should see the NameAndPassword custom UI ! Beware, "Sleep" won't be working as it is using another mechanisms file which is security.login.screensaver.

Handling Bugs & Crashes

Here we go, you made a modification to your code, the loginwindow doesn't reload and you're stuck on a black screen, you have an infinite loading spinner or a crashing loading spinner. Nothing really funny.

What can you do ? Mainly restore the original login system using the SSH connection.

If it is not done already, cd to the folder where are your security.login.console.txt files you saved earlier. And here type :

security authorizationdb write system.login.console < system.login.console.original.txt

Add directly after :

sudo killall SecurityAgent

sudo killall securityd

This will put instead of your custom mechanisms file the original one and will help the login system to reload. If nothing happens but you have access to the faulty custom login, make it crash and with those commands, it will reboot in its original version.

If it doesn't work ? Turn off the Mac and reboot it normally. It will load a normal system.login.console.

A few remarks

Here are a few advices and things I noticed that during all my experimentations.

  • When the plugin loads, it will not be able to update UI on a regular (or irregular basis). That means if you need to update the UI and want to see the change, you need to go back to the view showing all the users and click again on your session. In this case, the plugin seems to be loaded again and shows an updated UI (if ti was to be updated).
  • The plugin has very limited access to anything outside of its bundle. Finding a safe place to store your password is not easy.

Useful Stuff

Three Shell scripts which allow you to install or uninstall the original login system by simply running sh [filename].sh.

  • - Install your Plugin
  • - Uninstall your Plugin

Note : For both, you will need to update the location and the name of the build.

Command to show the SFAuthorizationPluginView without logging out :

/System/Library/CoreServices/Menu\ Extras/ -suspend

Restoring the original login system :

security authorizationdb write system.login.console < system.login.console.original.txt

sudo killall SecurityAgent

sudo killall securityd