Verify the Password using the AuthorizationCopyRights

Hi everyone,

I’m working on building a passwordless login system on macOS using the NameAndPassword module. As part of the implementation, I’m verifying if the password provided by the user is correct before passing it to the macOS login window.

Here’s the code snippet I’m using for authentication:

    // Create Authorization reference
    AuthorizationRef authorization = NULL;

    // Define Authorization items
    AuthorizationItem items[2];
    items[0].name = kAuthorizationEnvironmentPassword;
    items[0].value = (void *)password;
    items[0].valueLength = (password != NULL) ? strlen(password) : 0;
    items[0].flags = 0;
    items[1].name = kAuthorizationEnvironmentUsername;
    items[1].value = (void *)userName;
    items[1].valueLength = (userName != NULL) ? strlen(userName) : 0;
    items[1].flags = 0;

    // Prepare AuthorizationRights and AuthorizationEnvironment
    AuthorizationRights rights = {2, items};
    AuthorizationEnvironment environment = {2, items};

    // Create the authorization reference
    [Logger debug:@"Authorization creation start"];

    OSStatus createStatus = AuthorizationCreate(NULL, &environment, kAuthorizationFlagDefaults, &authorization);
    if (createStatus != errAuthorizationSuccess) {
        [Logger debug:@"Authorization creation failed"];
        return false;
    }
    

    // Set authorization flags (disable interaction)
    AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagExtendRights;

    // Attempt to copy rights
    OSStatus status = AuthorizationCopyRights(authorization, &rights, &environment, flags, NULL);

    // Free the authorization reference
    if (authorization) {
        AuthorizationFree(authorization, kAuthorizationFlagDefaults);
    }

    // Log the result and return
    if (status == errAuthorizationSuccess) {
        [Logger debug:@"Authentication passed"];
        return true;
    } else {
        [Logger debug:@"Authentication failed"];
        return false;
    }
}

This implementation works perfectly when the password is correct. However, if the password is incorrect, it tries to re-call the macOS login window, which is already open. even i though i did not used the kAuthorizationFlagInteractionAllowed flag. This causes the process to get stuck and makes it impossible to proceed.

I’ve tried logging the flow to debug where things go wrong, but I haven’t been able to figure out how to stop the system from re-calling the login window.

Does anyone know how to prevent this looping behavior or gracefully handle an incorrect password in this scenario? I’d appreciate any advice or suggestions to resolve this issue.

Thanks in advance for your help!

Answered by DTS Engineer in 816974022

Create a second mechanism that gets the password from the context and saves it, then add that mechanism near the end of the mechanisms array, after builtin:authenticate.

Share and Enjoy

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

That code is problematic regardless of the bigger issue here. You are passing the same items array to both the rights and environment parameter of AuthorizationCopyRights. That doesn’t make any sense. The items in that array are obviously environment items, which isn’t appropriate for the rights parameter. Rather, the rights parameter should contain a single item that’s the right you’re trying to acquire.

However, there’s no point in fixing that because using AuthorizationCopyRights for this task is not correct.

In general, I recommend that you not try to preflight this check. Rather, put the credential into the authorisation context and let the subsequent mechanisms in the mechanisms array do the final check [1]. If that fails, the system will retry, running the mechanisms from the start, and so you’ll get another go at this.

using the NameAndPassword module

That’s not a great place to start. For this sort of thing you’ll want to start with QAuthPlugins > LoginUIAuthPlugin.

Share and Enjoy

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

[1] Specifically, builtin:authenticate is the final check.

If that fails, the system will retry, running the mechanisms from the start, and so you’ll get another go at this.

The issue I’m facing is that I’m trying to implement a feature to save the password in the macOS Keychain (I haven’t fully reached that part yet—still figuring it out). However, if someone enters the wrong password, I want to ensure it doesn’t get saved in the Keychain. And there is no way for me know if the password is correct or not

Do you have any alternative suggestions or approaches to achieve this functionality? Your insights would be greatly appreciated!

Create a second mechanism that gets the password from the context and saves it, then add that mechanism near the end of the mechanisms array, after builtin:authenticate.

Share and Enjoy

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

Create a second mechanism that gets the password from the context and saves it, then add that mechanism near the end of the mechanisms array, after builtin:authenticate.

The Issue with this is that if someone changes the password, I want to show the password field again so that the user can enter his new password, but I cannot verify whether the stored password is correct.

Changes their password how?

This matters because, depending on where the password changing code is, you might be able to have it store the info you need to recognise this case. Critically, you’re going to want to store the password itself securely, because you could store a password generation number in a less secure, and hence more accessible, place.

Share and Enjoy

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

Changes their password how?

Currently I am trying to change the password from the User and group tab in the settings.

In the Future might connect to the AD also.

I don't think I can track if some changes their password.

OK.

In this case I think you can deal with this by adding a ‘did try this password’ property to the authorisation hints. Set it in the mechanism that tries the password and clear it in your post-builtin:authenticate authenticate mechanism. If your main mechanism runs and the flag is set, you know you didn’t make it to post-builtin:authenticate mechanism and thus it’s likely that the password is wrong.

If that doesn’t work, you can use lower-level APIs to ‘preflight’ the credential. One option is -[ODRecord verifyPassword:error:].

The drawback to that approach is that it assumes that the user has a simple password, but I think that’s going to be a requirement of your product anyway.

Share and Enjoy

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

Verify the Password using the AuthorizationCopyRights
 
 
Q