Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2006-403
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 403
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 403

Login and Authentication: Mac OS X's New Front Door

OS Foundations • 29:44

An extensible authentication mechanism is a cornerstone of system security, allowing users to identify themselves with more than just a username & password. Mac OS X makes it easy for developers to provide new modes of authentication such as biometrics, or token storage devices that integrate with all of the authentication-related components of the system. With Mac OS X Leopard, a new plugin mechanism allows developers to easily add their solutions to the Mac OS X login experience.

Speaker: Kevin Armstrong

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hi, welcome. My name is Kevin Armstrong, and today we're going to be talking about authorization and looking at how that's done, looking at a new API we're adding to make things a little easier for developers. And so let's get started. So what we're going to learn, we're going to-- well, the first thing is authorization. What is it? How is it used? Why do you want to use it?

What is an authorization plugin? We'll look at how those are written and how they run in the system. And then we'll introduce the SF authorization plugin view, which is new for Leopard, and go about--look at how one of those is written as well. So let's get started. What is authorization?

Well, authorization is a process where, by the user is unidentified, their credentials are gathered. Those credentials are authenticated to make sure the user is who they say they are. Permissions are checked to make sure they have the right to perform the operation. And if all that works out, then the right is granted.

What is this used for? Well, this is used to confirm that the user has given permission to the app to do something and has the permission to do that. And then it was performed a specific task such as adding a new user to the system, unlocking the screen after waking up from sleep, installing software, burning a CD, logging into the system, and stuff like that.

So why should you use authorization? Well, it allows a system administrator to control policy. So if they wanted to change the fact-- burning the CD so that only admins could do it, or that nobody could do it, that's possible, things like that. It also allows the system to use different authentication mechanisms, such as biometric scanners and card readers and things like that.

So how is authorization done in Mac OS X? Well, an application uses the security framework to ask for the right to perform a task. Now they do that by calling a few APIs. First is Authorization Create. This is how you create an authorization ref. And it takes three other parameters. And Apple recommends that you just set those to some defaults so that things are easy to-- so you don't have problems later on.

There's a technical Q&A article about this that you can read. But anyway, so right now with Authorization Create, we're going to pass in null, an empty environment, and default flags, and we'll get back the authorization ref.

[Transcript missing]

So once you've called authorization copyrights, the result will come back. And you'll just check the status, and if it's authorization success, then the user has authorized properly, provided their credentials, and you're now able to perform the task.

So if you need to get information from the authorization ref, say the user's ID or name, you can retrieve that in some cases with the authorization copy info. Again, it takes your authorization ref. It takes a tag, which is the name of the information you want to get back.

Or you can pass in null to get all the information available. And then you'll get back the information in the info parameter. Then once you've gotten that information, you can use it how you need to. So we've been talking about rights. So what is a right? Well, a right is a name privilege that an application requests on behalf of the user. And they're specified in the policy database.

Each write has a name and a dictionary which specifies how the write is to be evaluated. So here's an example of a simple write. This is the system burn write. It has a class and a comment. The class is set to allow, which means always allow this write. And the comment, of course, is a simple little description of what it does, authorization to burn media.

So this is how you control, you know, this is what the system checks to see if it's allowed to burn some media. Now if you set this to deny, you could prevent anybody from burning, and you can also change it so that only admins or users of a certain group could burn media.

Here's a little more complex write. This is the one used to install to an admin domain, you know, such as /applications. And here the user, the class is user, and it's a group is admin, so they have to be in the admin group to do this. The shared key controls whether this is shared amongst applications or, and then the timeout is set to 300 seconds. So after five minutes, this one will time out, and it's not shared amongst other apps.

So this isn't even more complicated, right? This is the right that's checked when somebody logs into the system. System login console. And the class here is evaluate mechanisms. And this means that the system will go through each of the mechanisms specified, make sure that the user is allowed by each one, and when it's done, only then are they allowed to log in. So here you can see the list of mechanisms. Now if you need to add a write to the system, you can use the authorization db.h. Now we really suggest you do use this.

It has the three functions here. Authorization write get, pass in the name, and you'll get back the definition. Authorization write set, and you pass in a definition. You have the ability to set some of the prompts that'll be shown in the standard authorization dialog. It'll provide even localizations for those prompts. And then authorization write remove if you're cleaning up the system and need to get rid of it or change it.

Now the benefits of using this API are that it makes modification easier and more convenient. It's also safer since you're not parsing the database yourself and making changes directly. It uses the authorization system so that it can ask for the proper permissions when necessary, so you don't have to write a privilege tool for your installer.

And when you create a right definition, it doesn't require admin privileges, but you do have to have a unique name. And one of the caveats here is that there is wildcard characters, so for instance, com.apple. That dot at the end is the wildcard, which means you can't add com.apple.blah.

If you want to look at the policy database on your computer right now, it's in the Etsy authorization file. And this is just an XML file that contains the information about authorization. Again, don't try to modify this file directly. So we've been talking about mechanisms, and I showed you the mechanism list. So what are they? Well, a mechanism is a path of execution through an authorization plugin. And each one in this list is specified by a plugin ID, a colon, a mechanism ID, and optionally comma privileged.

And the comma privilege specifies where it will run. GUI app, or GUI plugins and such, and if they don't need privileged rights, they should run in security agent, and you don't add the privileged. If they're going to need to run as root for some reason, then they'll run an authorization host.

Now as mechanisms run, each one runs alone and then the control is passed on to the next. And that happens when the set result is done. And when the mechanism sets a result of allow, control is passed on to the next mechanism. And so on and so forth until you get to the last one. During the execution of these mechanisms, there's two sets of information. There's context values and hint values. And that information also flows from the first to the last. So once control is passed to mechanism two, mechanism one can no longer set values or get values.

So context values are authoritative bits of data during the execution cycle. They're read and written by mechanisms, and they're used to transfer data from one to the next. And they have access controls on them so that the authorization copy info function, they will or will not be available to that.

Hint values are very similar. They are used to pass information, but there will be a way for applications to pass information into a mechanism, and that's done through the authorization environment. Two of the ones that are used commonly are the environment prompt and the environment icon, just to provide some customization of the standard authorization dialog.

So what's going on behind the scenes with an authorization? Well, when my application calls authorization copyrights, request is sent to the security server. And that is done by SecurityD, that is the security server now. So system preferences is passed to the security server. The security server then queries the policy database and gets the right, so it knows how to process and handle that.

Security server then launches security agent and authorization host in order to work with those applications to process the right. Security agent gets the non-privileged mechanisms, and authorization host gets the privileged ones. So when security agent is run, it'll put up the standard authorization dialogue, get the user's identity and credentials, and then it will write the context values, the identity credentials to the context.

It'll then call setResult, and that information will get passed over to the authorization host, and it will authenticate the credentials, and when it's done, it will call setResult, and then control will return to the security server. The security server will then return the result to the application, and the application can then check the status and perform the task.

So we've been talking about authorization plugins, so let's look at how to write one of those. So what you do is you create an authorization plugin using Coco's bundle template. And the first thing you'll need is the entry point function. The authorization plugin create takes three parameters. There are authorization callbacks, which you'll need to save for later. This is a structure with a list of function pointers that you use to talk to authorization hosts or security agent. The authorization plugin ref, which is just the value that you've chosen-- it's usually a pointer to an object or structure.

And then Authorization Plugin Interface is a list of functions that are in your plugin that you will return so that Authorization Host and Security Agent can communicate with your plugin. So let's look at that structure real quick. The first item in it is a version. This tells the Authorization Host and Security Agent which version you're running, which version of the structure you support, so it knows which functions you have.

And then there's a list of functions after that, and let's look at those. So Plugin Destroy, this one's kind of self-explanatory. This tells your plugin that it's being destroyed, and then it gives you a chance to clean up and release memory, stop talking to hardware, or whatever. Mechanism Create, this is where your ID comes in so you'll know which mechanism is about to be executed. You'll also get an Authorization Engine Ref, which is something you need to save because you'll pass that back to Authorization Host or Security Agent. And you'll return a Mechanism Ref, which is like the plugin ref. It's just the value of your choosing.

And you'll return a Mechanism Ref, which is like the plugin ref. It's just the value of your choosing. The mechanism invoke, when this is called, it tells the mechanism to run. And when you're finished, you'll call setResult. Now, if you're showing UI or something, you may want your UI to run on the run loop, which is fine. You can call setResult any time. One note is that when-- Once you call setResult, you'll no longer be able to read or write context values or hint values. And you can't do those either before your mechanism invoke is called.

Mechanism deactivate. As soon as you get this, as soon as possible, call did deactivate just to let the host know that you've You've received it. Mechanism Destroy, again, self-explanatory. It's just the means by-- just tells your mechanism that it's about to go away and that it should clean up anything. So let's look at the authorization callback structure that came in with Authorization Plugin Create.

Again, you should keep, you know, be sure to keep a pointer to this. And this has the functions like setResult, setContextValue, and so forth that we've been talking about along with some others. So setResult, this is, you know, you use this to allow or deny continuation of the authorization. Once it's called, you can't, you know, set context values, so be sure to set those beforehand.

context value accessors. These are get context value and set context value. And there's, like I said before, there's access control flags on the context values to allow them to be available to the application through authorization copy info. Two of them are authorization context flag extractable and context flag volatile. Now the hint values, you know, get hint value, set hint value again. Notice they don't have the context flags, so they can't read anything.

So once you've created your authorization plugin, you'll want to install it. Now they go into System Library, Core Services, Security Agent Plugins. And then you may want to add a right or change other rights in the policy database. So you can see here an example of adding an authorization-- or name and password invoke to a mechanism list, or name and password invoke and an authorization to it to make sure that the credentials came in correctly.

So now let's talk about the SF authorization plugin view. Why are we doing this? Well, the first reason is we wanted to eliminate the need for developers to reproduce Apple's authorization dialogues. There's a lot of-- in the past when this has been done, they've had interesting UI bits. And because of that, we want to create a unified user experience for our customers. And it also allows us to change our UI and let people continue to see a consistent interface.

And we can also add functionality and keep the SPIs that we use private. So here's an example of what this will do. This is the login window. And you may notice that the password looks a little different than before. And that's because this portion of it was replaced by the name and password example that I've written that's going to be available.

And the same thing with the standard authorization dialogue. This section here has been replaced. Now as a developer, if you want to provide UI for a fingerprint scanner or card reader of some sort, you can simply provide an SF authorization plugin and replace these portions. And this is what we wanted to do.

So let's look at how to write one of these. Well, the first thing you do is you add a-- you add a class to your authorization plugin and make it a subclass of the SF authorization plugin view. And we provide a couple of views. We have an identity and credentials view and just a credentials view. That goes back to which one of the dialogues was asking for it. There's two methods you have to override, button pressed and view for type.

So let's look at button pressed real quick. Button pressed, you'll be told which button was pressed, like either the OK. Cancel or login. And when you get that, you'll need to set the user's identity and password and then call set result. Well, in this case, password. In the case of a fingerprint renderer, you might need to write the credentials for the fingerprint or how that came in or whatever. If it was cancel, then you just say the user canceled. View for type is where you return the appropriate view based on which was requested.

So if you're asking for the identity credentials, you'd return the appropriate view and so forth. The next thing to do in your plugin is to instantiate the subclass. So you have my subclass Alec in it with callbacks. And here you can use the callbacks and the engine ref that you got from authorization plugin create and mechanism create. And you can use the callbacks and the engine ref that you got And then the hard part.

This is where you have to display the authorization dialog so that things show up on the screen and the user can use the views that you've provided. And it's just simply my object display view. We've tried to make it very simple, yet very powerful. So, just as a recap on this, what do you need to do? Well, you create an authorization plugin.

You create an SF authorization plugin view subclass, you instantiate the subclass, and you call display view. And that will cause the appropriate dialog to come up on screen and your view will be added to it and you can use it however you want. So let's fill out the rest of the subclass.

In Cocoa, there's this concept of a keyboard loop, which is when you're using the Tab key, you'll move through the controls of the dialog. Most everybody's probably familiar with that. And so we have a few methods here to help that along. FirstKeyView and LastKeyView, those will be used to set up the loop, and in some cases, the dialogs will do this automatically so that your methods may not actually be called.

FirstResponderView, however, will get called. And this is used to determine which one of the controls you want to have active right away. So keyboard loop example. As I said, in the case of this UI, the name is the FirstKeyView and the password is the LastKeyView. You just simply return those. In the case of the FirstResponder example, this gets a little more interesting.

So if you have no name available, you'd want the user to be able to enter their name immediately. So you would set the first responder view to the name. If you have a name, Then you'll set it to the password view, and so you can see that in the little example code there.

There are times when it's appropriate for your controls to be active, and the authorization dialogs will call setEnabled to tell your controls when to be enabled and when not to be enabled. So you can see here, all it is is a simple "tell the text field in the password text field to setEnabled with the appropriate flag."

Now, there are other times when you'll need to configure your UI. Say you might have a countdown timer or some other... There's a lot of things going on, you know, animation or something in your view. And what you'll do is, these three are used for that. WillActivateWithUser will be passed in to tell you that your view is about to be activated. If the end user information is not nil, it'll probably contain the user's name so that you can add it to your UI. Once the view is ready to be used, you'll get a DidActivate. And when it's no longer in use, you'll get a DidDeactivate.

Now if you need to have multiple stages or change the view for a particular reason, you can call Update View. This will allow you to provide a new view. The dialogs will call View for Type again, and you'll get the chance to provide a new view to the dialog, and a new one will show up. And then if you need to disable the OK or Cancel buttons, you can use Set Button Enabled to do that. So let's go for a quick demo.

So here we have the name and password plugin. Look at the-- class interface real quick. So you can see I have a number of views here. This is the Identity and Credentials view. We have a Password view and some other variables. The amount of code involved is really not a whole lot, but this does some pretty powerful stuff. So here's the button pressed. You can see that if I'm using the Identity and Credentials view, use the user name string from that. Otherwise, we'll use the one that was passed in. We'll write out the context values.

In the appropriate cases, the first key view. This is also available as example code, so you won't have to try to copy it all down right now. First responder view. Again, we'll check to see if the text field has got any text in it, and if not, we'll use that as the one that is available to the user to use first. Otherwise, we'll use the password. Last key view. Set Enabled: Again, we're just passing along to the various controls the Set Enabled.

Here we're saving the name and adding it to the name field if it's been passed in with the "will activate with user". View for Type returns the appropriate view. And our NIT with callbacks doesn't have anything else to do, but it's there. Let's look at an example of this real quick. So here I have a little simple app. Let's remove this real quick.

So I've got a bundle, the name and password bundle, I have a mechanism name for it. But before I do that, also notice the right name test right, I'm going to add this right to the policy database. So right now there's no right to find. So if I add that, notice it didn't require authorization. But it added one that's called, with a class of allow and a comment for testing authorization plugin. So if I test that, the authorization is successful.

Now a little bit more complex right, we'll add that. And now in this case, you notice that we're being asked to modify the right, so I have to authorize that. So now we have a class of user comment, the same comment, and now it requires group admin. So if I test that, and I change this to test user 001.

So now it knows that it's not, that test user is not an admin and I need to pay an admin. So let's try that again with... There, so authorization was successful at that point. So now if I do an even more complicated write, This one I have a mechanism list. And we have the name and password bundle. Get rid of that. Well, that's right. We're going to use the name and password plugin that we wrote already and looked at the code for.

And we're going to use the invoke mechanism for that. And then we're going to authenticate what we get. So test that. And so here you can see the new view that's been added to the dialog. And again, we have all the controls here and stuff. Oh, it didn't work great. There are some small issues still.

But you can see it failed. Test that again. There. Authorization was successful that time. So just a simple way to add-- A UI to the standard authorization dialogs and the login dialogs and all the Apple-provided dialogs and use those instead of having to write your own, having to replace Apple's dialogs. And also give you a bit of an example of how the rights work in the policy database and why you should use them. So, go back over here. Back to the slides.

So if you want to get more information, the authorization plugin reference is available on the website. It's probably also on your-- Documentation in your developer install. There's authorization plug-in examples at developer example security. There's one there for a banner sample that will put up a banner in front of log in that you'll have to click through. You can set the text on that.

There's also another one. There's a Tech Note authorization for everyone that's useful. And then be careful when using authorization create. The technical Q&A article tells you why. To use the default values. And then the name and password example plug-in is available in the example code for this year's WWDC.