## Autorisation XPC Apple propose également une autre façon d'authentifier si le processus de connexion a les **permissions pour appeler une méthode XPC exposée**. Lorsqu'une application a besoin d'**exécuter des actions en tant qu'utilisateur privilégié**, au lieu d'exécuter l'application en tant qu'utilisateur privilégié, elle installe généralement en tant que root un HelperTool en tant que service XPC qui peut être appelé depuis l'application pour effectuer ces actions. Cependant, l'application appelant le service doit avoir suffisamment d'autorisations. ### ShuoldAcceptNewConnection toujours YES Un exemple peut être trouvé dans [EvenBetterAuthorizationSample](https://github.com/brenwell/EvenBetterAuthorizationSample). Dans `App/AppDelegate.m`, il essaie de **se connecter** au **HelperTool**. Et dans `HelperTool/HelperTool.m`, la fonction **`shouldAcceptNewConnection`** **ne vérifiera pas** les exigences indiquées précédemment. Elle renverra toujours YES: ```objectivec - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection // Called by our XPC listener when a new connection comes in. We configure the connection // with our protocol and ourselves as the main object. { assert(listener == self.listener); #pragma unused(listener) assert(newConnection != nil); newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)]; newConnection.exportedObject = self; [newConnection resume]; return YES; } ``` Pour plus d'informations sur la façon de configurer correctement cette vérification : {% content-ref url="macos-xpc-connecting-process-check.md" %} [macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md) {% endcontent-ref %} ### Droits d'application Cependant, il y a une certaine **autorisation en cours lorsqu'une méthode du HelperTool est appelée**. La fonction **`applicationDidFinishLaunching`** de `App/AppDelegate.m` créera une référence d'autorisation vide après le démarrage de l'application. Cela devrait toujours fonctionner.\ Ensuite, il essaiera d'**ajouter certains droits** à cette référence d'autorisation en appelant `setupAuthorizationRights`: ```objectivec - (void)applicationDidFinishLaunching:(NSNotification *)note { [...] err = AuthorizationCreate(NULL, NULL, 0, &self->_authRef); if (err == errAuthorizationSuccess) { err = AuthorizationMakeExternalForm(self->_authRef, &extForm); } if (err == errAuthorizationSuccess) { self.authorization = [[NSData alloc] initWithBytes:&extForm length:sizeof(extForm)]; } assert(err == errAuthorizationSuccess); // If we successfully connected to Authorization Services, add definitions for our default // rights (unless they're already in the database). if (self->_authRef) { [Common setupAuthorizationRights:self->_authRef]; } [self.window makeKeyAndOrderFront:self]; } ``` La fonction `setupAuthorizationRights` de `Common/Common.m` stockera dans la base de données d'autorisation `/var/db/auth.db` les droits de l'application. Notez comment elle n'ajoutera que les droits qui ne sont pas encore dans la base de données : ```objectivec + (void)setupAuthorizationRights:(AuthorizationRef)authRef // See comment in header. { assert(authRef != NULL); [Common enumerateRightsUsingBlock:^(NSString * authRightName, id authRightDefault, NSString * authRightDesc) { OSStatus blockErr; // First get the right. If we get back errAuthorizationDenied that means there's // no current definition, so we add our default one. blockErr = AuthorizationRightGet([authRightName UTF8String], NULL); if (blockErr == errAuthorizationDenied) { blockErr = AuthorizationRightSet( authRef, // authRef [authRightName UTF8String], // rightName (__bridge CFTypeRef) authRightDefault, // rightDefinition (__bridge CFStringRef) authRightDesc, // descriptionKey NULL, // bundle (NULL implies main bundle) CFSTR("Common") // localeTableName ); assert(blockErr == errAuthorizationSuccess); } else { // A right already exists (err == noErr) or any other error occurs, we // assume that it has been set up in advance by the system administrator or // this is the second time we've run. Either way, there's nothing more for // us to do. } }]; } ``` La fonction `enumerateRightsUsingBlock` est celle utilisée pour obtenir les autorisations des applications, qui sont définies dans `commandInfo`: ```objectivec static NSString * kCommandKeyAuthRightName = @"authRightName"; static NSString * kCommandKeyAuthRightDefault = @"authRightDefault"; static NSString * kCommandKeyAuthRightDesc = @"authRightDescription"; + (NSDictionary *)commandInfo { static dispatch_once_t sOnceToken; static NSDictionary * sCommandInfo; dispatch_once(&sOnceToken, ^{ sCommandInfo = @{ NSStringFromSelector(@selector(readLicenseKeyAuthorization:withReply:)) : @{ kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.readLicenseKey", kCommandKeyAuthRightDefault : @kAuthorizationRuleClassAllow, kCommandKeyAuthRightDesc : NSLocalizedString( @"EBAS is trying to read its license key.", @"prompt shown when user is required to authorize to read the license key" ) }, NSStringFromSelector(@selector(writeLicenseKey:authorization:withReply:)) : @{ kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.writeLicenseKey", kCommandKeyAuthRightDefault : @kAuthorizationRuleAuthenticateAsAdmin, kCommandKeyAuthRightDesc : NSLocalizedString( @"EBAS is trying to write its license key.", @"prompt shown when user is required to authorize to write the license key" ) }, NSStringFromSelector(@selector(bindToLowNumberPortAuthorization:withReply:)) : @{ kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.startWebService", kCommandKeyAuthRightDefault : @kAuthorizationRuleClassAllow, kCommandKeyAuthRightDesc : NSLocalizedString( @"EBAS is trying to start its web service.", @"prompt shown when user is required to authorize to start the web service" ) } }; }); return sCommandInfo; } + (NSString *)authorizationRightForCommand:(SEL)command // See comment in header. { return [self commandInfo][NSStringFromSelector(command)][kCommandKeyAuthRightName]; } + (void)enumerateRightsUsingBlock:(void (^)(NSString * authRightName, id authRightDefault, NSString * authRightDesc))block // Calls the supplied block with information about each known authorization right.. { [self.commandInfo enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { #pragma unused(key) #pragma unused(stop) NSDictionary * commandDict; NSString * authRightName; id authRightDefault; NSString * authRightDesc; // If any of the following asserts fire it's likely that you've got a bug // in sCommandInfo. commandDict = (NSDictionary *) obj; assert([commandDict isKindOfClass:[NSDictionary class]]); authRightName = [commandDict objectForKey:kCommandKeyAuthRightName]; assert([authRightName isKindOfClass:[NSString class]]); authRightDefault = [commandDict objectForKey:kCommandKeyAuthRightDefault]; assert(authRightDefault != nil); authRightDesc = [commandDict objectForKey:kCommandKeyAuthRightDesc]; assert([authRightDesc isKindOfClass:[NSString class]]); block(authRightName, authRightDefault, authRightDesc); }]; } ``` Cela signifie qu'à la fin de ce processus, les autorisations déclarées dans `commandInfo` seront stockées dans `/var/db/auth.db`. Notez comment vous pouvez trouver pour **chaque méthode** qui nécessitera une **authentification**, le **nom de la permission** et le **`kCommandKeyAuthRightDefault`**. Ce dernier **indique qui peut obtenir ce droit**. Il existe différents domaines pour indiquer qui peut accéder à un droit. Certains d'entre eux sont définis dans [AuthorizationDB.h](https://github.com/aosm/Security/blob/master/Security/libsecurity\_authorization/lib/AuthorizationDB.h) (vous pouvez trouver [tous ici](https://www.dssw.co.uk/reference/authorization-rights/)), mais en résumé :
Nom | Valeur | Description |
---|---|---|
kAuthorizationRuleClassAllow | allow | N'importe qui |
kAuthorizationRuleClassDeny | deny | Personne |
kAuthorizationRuleIsAdmin | is-admin | L'utilisateur actuel doit être un administrateur (dans le groupe admin) |
kAuthorizationRuleAuthenticateAsSessionUser | authenticate-session-owner | Demandez à l'utilisateur de s'authentifier. |
kAuthorizationRuleAuthenticateAsAdmin | authenticate-admin | Demandez à l'utilisateur de s'authentifier. Il doit être un administrateur (dans le groupe admin) |
kAuthorizationRightRule | rule | Spécifiez des règles |
kAuthorizationComment | comment | Spécifiez des commentaires supplémentaires sur le droit |