trilemma-dev/SwiftAuthorizationSample

Always asking auth for [Auth required]

Closed this issue · 8 comments

Hi,

Thanks for your hard work on this project, I have a question regarding commands with auth required, is it possible to retain the user authentication instead of askin login each time we trigger the "Run" button ?

Thanks

Yes, assuming you mean you're looking to track whether a user has previously authorized the rights before.

The key piece is to make use of XPCRequestContext.effectiveUserID to know which user made the current request.

Here's a really basic form where the server keeps it in memory and this implementation is not thread safe. But the same general approach could be made thread safe or even persisted to disk (assuming you're comfortable assuming user ids are stable over time):

private static var previouslyAuthorizedUsers = Set<uid_t>()

static func run(message: AllowedCommandMessage) throws -> AllowedCommandReply {
        // Prompt user to authorize if needed
        if message.command.requiresAuth,
           !previouslyAuthorizedUsers.contains(XPCRequestContext.effectiveUserID) {
            if let authorization = message.authorization {
                let rights = try authorization.requestRights([SharedConstants.exampleRight],
                                                             environment: [],
                                                             options: [.interactionAllowed, .extendRights])
                if !rights.contains(where: { $0.name == SharedConstants.exampleRight.name }) {
                    throw AllowedCommandError.authorizationFailed
                }
                
                previouslyAuthorizedUsers.insert(XPCRequestContext.effectiveUserID)
            } else {
                throw AllowedCommandError.authorizationMissing
            }
        }
      
        <# rest of implementation remains unchanged #>

Thanks it works well 👍
Is it possible that the authorization expires ? or is it valid forever ?
And what if the authorization expires is there a way to track that ?
Thanks again !

Taking a step back, what are you trying to use a custom right for? Due to the questions you're asking, I suspect this may not be the right approach. There are valid cases use cases, but they're rather uncommon.

To directly answer your questions:

Is it possible that the authorization expires ?

Yes

or is it valid forever ?

It can be, it depends on how the right is defined.

And what if the authorization expires is there a way to track that ?

Yes, you can check if an existing Authorization instance contains a right by requesting rights for it without allowing user interaction.

I'm doing almost what your sample has been designed for, I execute a command from the helper tool.
I just want to avoid user interaction each time I have to execute the command, this is why I have asked you how to save the user authorization.
But with your previouslyAuthorizedUsers method which is external to all the libraries that you have built we only save an UInt32 id, so I was wondering if it is possible to check if the Authorization related to the id is still valid.

I also have tried

authorization.requestRights([SharedConstants.commandRight],
                                                     environment: [],
                                                     options: []) // .interactionAllowed, .extendRights

but I have an error SecureXPC.HandlerError.UnderlyingError.unavailableNotEncoded

I just want to avoid user interaction each time I have to execute the command

Authorization doesn't ever need to be required, the sample is showing how to self restrict functionality if you so choose. If you never want to require it, don't do any self restriction.

Do you want to require user authorization some times, but not other times?

I want to play with pmset which is sudo only normally

You're confusing two different concepts:

  1. Authorization required by macOS to install a privileged helper tool which will run as root and therefore can use functionality such as pmset.
    • This can be handled for you by Blessed package plus the build configuration and script described in this sample.
  2. Authorization which is optionally chosen to be performed by an application and which grants no macOS related privileges.

To make use of functionality that requires sudo privileges means you need to do #1. There's no need to make use of #2 at all, but you may additionally do so if you would like.


This issue you opened is about #2 and will not be of any help to perform actions which require root. The sample app chooses to use authorization to restrict access to a couple of things which happen to require root permissions, but the fact they require root permission is not relevant.

From the README:

Two of the commands say "[Auth Required]" and when run will require you to provide an admin password. This is done to demonstrate how, if you so desire, you can self-restrict access to portions of your helper tool.

In the source code:

/// Whether providing this arg to `systemsetup` should require additional user authentication.
///
/// This is completely arbitrary and was just done for example purposes.

Does this make sense?

Oh yes sorry, it makes sense now thanks !