Article

Using Authorization Plug-ins

Extend authorization services with plug-ins.

Overview

To install an authorization plug-in, you write the plug-in using the API described in this document, install the bundle in /Library/Security/SecurityAgentPlugins, and use the AuthorizationRightSet function to add an entry to the authorization policy database that references the plug-in. The authorization policy database contains a set of rules that the Security Server uses to authorize rights for a user. Most of the rules directly specify the criteria to allow or deny access; however, some reference external code (referred to as authorization mechanisms) that define the behavior. The authorization database is described in The Policy Database section of Authorization Services Programming Guide. To invoke a plug-in, you pass the name of the database entry that references that plug-in in the rights parameter of the AuthorizationCopyRights function.

A typical use for authorization plug-ins is to implement policies that are not included in the standard authorization configuration. For example, you could write a plug-in that authorizes a user to send a fax by requiring a personal identification number (PIN) for a specific fax machine.

A plug-in’s main entry point must be the function AuthorizationPluginCreate, which exchanges the plug-in’s interface (through the AuthorizationPluginInterface structure) and the authorization interface of the Security Server (using the AuthorizationCallbacks structure).

When you add a policy to the authorization policy database, it can refer to any number of plug-ins. Each plug-in includes one or more authorization mechanisms, where a mechanism is a code module that performs one step in the authorization process.

For example, if you wrote a policy for sending faxes that required users to select the fax machine they wanted to use and enter a PIN for that machine, you might name the policy com.ifoo.ifax.send. To implement the policy, you could write a plug-in called SendFaxPlugin that contains two mechanisms: SelectFaxMachine and GetUserPIN. You would add your plug-in code to the folder /Library/Security/SecurityAgentPlugins as a bundle called SendFaxPlugin.bundle and you would use the AuthorizationRightSet function to add the lines shown below to the authorization policy database:

<key>com.ifoo.ifax.send</key>
        <dict>
            <key>class</key>
            <string>evaluate-mechanisms</string>
            <key>comment</key>
            <string>Rule to evaluate whether user has right  to
                    use a specific fax machine.
            </string>
            <key>mechanisms</key>
            <array>
                <string>SendFaxPlugin:SelectFaxMachine</string>
                <string>SendFaxPlugin:GetUserPIN</string>
            </array>
        </dict>

Notice that each plug-in is identified by the name of the plug-in, a colon, and the name of the mechanism; for example SendFaxPlugin:SelectFaxMachine where SelectFaxMachine is a mechanism in the plug-in SendFaxPlugin. The keys used in the dictionary entry are listed in Authorization Name Tags plus those in the file AuthorizationTagsPriv.h. The latter is not part of the public API. Apple reserves the right to change this file or its contents with future releases.

The Security Server loads plug-ins into a separate process—a plug-in host—to isolate the process of authorization from the client. There are two plug-in hosts:

  • One runs as an anonymous user and can be used to communicate with the user, for example to ask for a password.

  • One runs with root privileges to perform privileged operations.

In this document, the portion of the Security Server that deals with authorization and authentication, together with the plug-in hosts, is referred to as the authorization engine.

To have a specific mechanism run with root privileges, add a comma and the word privileged to the mechanism name; for example:

<string>SendFaxPlugin:ChangeUserPIN,privileged</string>

MechanismInvoke function, passing the plug-in name:mechanism name for that mechanism.

The mechanism calls the SetResult function to report the authorization decision. The authorization engine does not consider the authorization complete and approved until all the mechanisms have returned a positive (kAuthorizationResultAllow) authorization decision, one of the mechanisms has returned a negative (kAuthorizationResultDeny) decision, the maximum number of retries has been reached (kAuthorizationResultUndefined), or the user has canceled the attempt (kAuthorizationResultUserCanceled).

Mechanisms in the authorization can communicate auxiliary information by setting and getting hints and context data. Hints are data values for use during authorization; for example, you can use a hint to pass an intermediate value from one mechanism to a subsequent mechanism. They are not preserved as part of the authorization result. Context data is information that can be useful to an application, such as a user name entered by the user during the authorization process. Context data can be added, read, or modified by each mechanism in the authorization and is preserved by the Security Server. Context data can also be made available to the authorization client after authorization is complete. See SetHintValue and SetContextValue for more information on hints and context data.

When the authorization plug-in sets context data, it tags the data with a flag that specifies whether the information should be returned to the authorization client upon request (by using the AuthorizationCopyInfo function) or whether it’s restricted to the mechanisms involved in the authorization.

When the authorization engine needs an authorization decision based on a policy that belongs to the plug-in, the authorization engine calls each mechanism belonging to that policy in turn, in the order they are listed in the policy database. For each mechanism, the authorization engine calls the plug-in’s MechanismInvoke function, passing the plug-in name:mechanism name for that mechanism.

The mechanism calls the SetResult function to report the authorization decision. The authorization engine does not consider the authorization complete and approved until all the mechanisms have returned a positive (kAuthorizationResultAllow) authorization decision, one of the mechanisms has returned a negative (kAuthorizationResultDeny) decision, the maximum number of retries has been reached (kAuthorizationResultUndefined), or the user has canceled the attempt (kAuthorizationResultUserCanceled).

Mechanisms in the authorization can communicate auxiliary information by setting and getting hints and context data. Hints are data values for use during authorization; for example, you can use a hint to pass an intermediate value from one mechanism to a subsequent mechanism. They are not preserved as part of the authorization result. Context data is information that can be useful to an application, such as a user name entered by the user during the authorization process. Context data can be added, read, or modified by each mechanism in the authorization and is preserved by the Security Server. Context data can also be made available to the authorization client after authorization is complete. See SetHintValue and SetContextValue for more information on hints and context data.

When the authorization plug-in sets context data, it tags the data with a flag that specifies whether the information should be returned to the authorization client upon request (by using the AuthorizationCopyInfo function) or whether it’s restricted to the mechanisms involved in the authorization.