Vérification de l’accès dans le code

Le seul moment où vous n’avez pas besoin de vous préoccuper des concepts de sécurité, c’est lorsque vous écrivez du code qui devrait être exécuté par un utilisateur avec le rôle de sécurité Administrateur système. Comme ce rôle est tout puissant et ne peut pas être modifié, vous pouvez être assuré que l’utilisateur peut tout faire. Dans tous les autres cas, vous devez tenir compte de la manière dont la sécurité est appliquée.

  • Si vous créez une application client, vous devez évaluer les privilèges de l’utilisateur pour une table ou pour un enregistrement de table spécifique et contrôler les commandes que vous activez. Si un utilisateur n’est pas autorisé à créer une table, vous pouvez désactiver l’interface utilisateur dans votre application pour permettre la création d’une nouvelle table de ce type. S’ils ne disposent pas d’un accès en lecture à une table, votre application client peut choisir de ne pas afficher les composants liés à l’affichage des listes de ce type de table.

  • Si vous écrivez un plug-in synchrone, vous ne pouvez pas tenter une opération sur les données et supprimer l’exception. Toute opération qui échoue dans un plug-in synchrone entraîne l’annulation de l’ensemble de la transaction de données. Si une partie du processus est facultative en fonction des privilèges de l’utilisateur, vous devez d’abord vérifier les privilèges de l’utilisateur.

Il existe deux stratégies que vous pouvez appliquer pour détecter les opérations qu’un utilisateur peut effectuer :

  • Tester les enregistrements de table individuelle
  • Vérifier les privilèges de sécurité de l’utilisateur

Ces stratégies sont décrites ci-dessous.

Tester les enregistrements de table individuelle

L’interaction de l’utilisateur avec des enregistrements de table spécifiques commence généralement par une requête. Si un utilisateur n’a accès à aucun enregistrement pour cette table, la requête ne renvoie aucun enregistrement et il n’y a rien d’autre que l’utilisateur puisse tenter, hormis créer un enregistrement. Tester si l’utilisateur peut créer un nouvel enregistrement nécessite l’utilisation de l’autre stratégie (mentionnée ci-dessus) pour vérifier les privilèges de sécurité de l’utilisateur.

Cependant, si l’utilisateur a réussi à récupérer les enregistrements de table à l’aide d’une requête, vous pouvez ensuite tester un enregistrement à l’aide du message RetrievePrincipalAccess.

La méthode statique GetAccessRights suivante utilise le SDK de la classe RetrievePrincipalAccessRequest pour extraire un ensemble de droits d’accès qu’un utilisateur, une équipe ou une organisation a pour un enregistrement avec AccessRights Enum.

/// <summary>
/// Gets which access rights a user, team, or organization has for a specific record.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userOrTeamOrOrganization">The user, team, or organization to check</param>
/// <param name="entity">A reference to the entity to check.</param>
/// <returns>The access rights the user can perform.</returns>
static AccessRights GetAccessRights(
        IOrganizationService service,
        EntityReference userOrTeamOrOrganization,
        EntityReference entity)
{
    var request = new RetrievePrincipalAccessRequest()
    {
        Principal = userOrTeamOrOrganization,
        Target = entity
    };

    var response = (RetrievePrincipalAccessResponse)service.Execute(request);

    return response.AccessRights;
}

Avec la valeur retournée par cette méthode, vous pouvez utiliser la méthode Enum.HasFlag pour renvoyer une valeur booléenne lorsque l’utilisateur a accès pour effectuer des opérations spécifiques sur la table.

Le code suivant extrait montre comment utiliser la méthode statique GetAccessRights ci-dessus pour tester si un utilisateur a accès pour ajouter des enregistrements à un enregistrement de compte à l’aide du membre AppendToAccess.

var whoIAm = (WhoAmIResponse)service.Execute(new WhoAmIRequest());

var meRef = new EntityReference("systemuser", whoIAm.UserId);

QueryExpression query = new("account") { 
        ColumnSet = new ColumnSet("accountid"),
        TopCount = 1
};

EntityCollection accounts = service.RetrieveMultiple(query);

EntityReference accountRef = accounts
    .Entities
    .FirstOrDefault()
    .ToEntityReference();

AccessRights rights = GetAccessRights(service, meRef, accountRef);

var canAppendTo = rights.HasFlag(AccessRights.AppendToAccess);

Avec l’accès à un enregistrement de table, vous pouvez utiliser ces droits d’accès renvoyés pour tester toutes les opérations qui s’appliquent à cet enregistrement. Mais ce test n’inclut pas les fonctionnalités qui s’appliquent à d’autres opérations, telles que la création d’un enregistrement ou tout autre privilège qui n’est pas lié à une table spécifique. Pour ces opérations, vous devez Vérifier les privilèges de sécurité d’un utilisateur.

Obtenir des principaux avec accès à un enregistrement

Certaines opérations sur les données nécessitent qu’un autre utilisateur ait accès à un enregistrement. Si vous n’avez qu’un utilisateur, une équipe ou une organisation spécifique, vous pouvez tester l’autre utilisateur à l’aide du message RetrievePrincipalAccess.

Toutefois, si vous avez besoin d’une liste de tous les utilisateurs, équipes ou organisations avec lesquels un enregistrement a été partagé, utilisez le message RetrieveSharedPrincipalsAndAccess. RetrieveSharedPrincipalsAndAccess fournit des détails sur les droits d’accès de chaque utilisateur, équipe ou organisation, car l’enregistrement a été partagé avec eux.

La méthode statique GetSharedPrincipalsAndAccess suivante utilise les classes RetrieveSharedPrincipalsAndAccessRequest et RetrieveSharedPrincipalsAndAccessResponse pour renvoyer un tableau de données PrincipalAccess avec des détails sur les principaux et leur accès en raison du partage de l’enregistrement avec eux.

/// <summary>
/// Returns details about access principals have because a record was shared with them.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="target">The record to check</param>
/// <returns>The principal access data for each user, team, or organization</returns>
static PrincipalAccess[] GetSharedPrincipalsAndAccess(
    IOrganizationService service,
    EntityReference target)
{
    var request = new RetrieveSharedPrincipalsAndAccessRequest()
    {
        Target = target
    };

    var response = (RetrieveSharedPrincipalsAndAccessResponse)service.Execute(request);

    return response.PrincipalAccesses;
}

Vérifier les privilèges de sécurité d’un utilisateur

Lorsque vous n’avez pas d’enregistrement de table spécifique à tester, par exemple si un utilisateur peut créer un enregistrement de table, vous devez vous fier à la vérification des privilèges de sécurité de l’utilisateur. Ces privilèges sont stockés dans la table Privilege.

Il existe près de 1 000 privilèges individuels dans la base de données Dataverse et le nombre augmente avec chaque table ajoutée au système. Vous pouvez récupérer une liste des privilèges disponibles dans votre environnement en exécutant la requête FetchXML suivante.

<fetch version='1.0' distinct='true' no-lock='true' >
  <entity name='privilege' >
    <attribute name='name' />
  </entity>
</fetch>

Conseil

Le générateur FetchXML XrmToolBox est un outil utile pour composer et tester des requêtes FetchXML.

La valeur de l’attribut name suit ce modèle de convention d’affectation de noms lorsque le privilège s’applique aux tables : « prv + Verbe + Table SchemaName ». Le verbe peut correspondre à l’une des options suivantes : Ajouter, Ajouter à, Attribuer, Créer, Effacer, Partager, Écrire.

En plus des privilèges pour les tables, il existe moins de 100 autres privilèges spéciaux qui ne sont pas associés aux tables. Vous pouvez utiliser la requête suivante pour récupérer ces privilèges.

<fetch version='1.0' distinct='true' no-lock='true' >

<entity name='privilege' >
  <attribute name='name' />
  <filter>
    <condition attribute='name' operator='not-begin-with' value='prvAppend' />
    <condition attribute='name' operator='not-begin-with' value='prvAssign' />
    <condition attribute='name' operator='not-begin-with' value='prvCreate' />
    <condition attribute='name' operator='not-begin-with' value='prvDelete' />
    <condition attribute='name' operator='not-begin-with' value='prvRead' />
    <condition attribute='name' operator='not-begin-with' value='prvShare' />
    <condition attribute='name' operator='not-begin-with' value='prvWrite' />
  </filter>
</entity>

</fetch>

Utilisez ces messages pour récupérer des privilèges par ID ou nom de privilège. Ils incluent les privilèges que l’utilisateur peut avoir des équipes.

Message Fonction de l’API Web
Classe de requête du SDK
RetrieveUserPrivilegeByPrivilegeId Fonction RetrieveUserPrivilegeByPrivilegeId
Classe RetrieveUserPrivilegeByPrivilegeIdRequest
RetrieveUserPrivilegeByPrivilegeName Fonction RetrieveUserPrivilegeByPrivilegeName
Classe RetrieveUserPrivilegeByPrivilegeNameRequest
RetrieveUserSetOfPrivilegesByIds Fonction RetrieveUserSetOfPrivilegesByIds
Classe RetrieveUserSetOfPrivilegesByIdsRequest
RetrieveUserSetOfPrivilegesByNames Fonction RetrieveUserSetOfPrivilegesByNames
Classe RetrieveUserSetOfPrivilegesByNamesRequest

Exemple : Vérifier si un utilisateur a un privilège

Les exemples suivants illustrent l’utilisation du message RetrieveUserPrivilegeByPrivilegeName. Ce message récupère la liste des privilèges d’un utilisateur système (utilisateur) à partir de tous les rôles directs associés à l’utilisateur système et de tous les rôles indirects associés aux équipes dont l’utilisateur système est membre en fonction du nom de privilège spécifié.

La méthode statique HasPrivilege suivante renvoie si l’utilisateur dispose du privilège nommé.

/// <summary>
/// Returns whether specified user has a named privilege
/// </summary>
/// <param name="service">The IOrganizationService instance to use.</param>
/// <param name="systemUserId">The Id of the user.</param>
/// <param name="privilegeName">The name of the privilege.</param>
/// <returns></returns>
static bool HasPrivilege(IOrganizationService service,
        Guid systemUserId,
        string privilegeName)
{
    var request = new
        RetrieveUserPrivilegeByPrivilegeNameRequest
    {
        PrivilegeName = privilegeName,
        UserId = systemUserId
    };
    var response =
        (RetrieveUserPrivilegeByPrivilegeNameResponse)service
        .Execute(request);
    if (response.RolePrivileges.Length > 0)
    {
        return true;
    }
    return false;
}

Pour plus d’informations :

Récupérer les privilèges d’un rôle de sécurité

Vous pouvez récupérer les privilèges associés à un rôle de sécurité.

La méthode statique GetRolePrivileges suivante récupère les privilèges associés à un rôle.

/// <summary>
/// Retrieves the privileges for a role.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="roleId">The id of the role</param>
/// <returns>Privilege records associated to the role</returns>
static EntityCollection GetRolePrivileges(IOrganizationService service, Guid roleId) {

    Relationship roleprivileges_association = new("roleprivileges_association");

    var relationshipQueryCollection = new RelationshipQueryCollection();

    var relatedPrivileges = new QueryExpression("privilege")
    {
        ColumnSet = new ColumnSet("name")
    };

    relationshipQueryCollection.Add(roleprivileges_association, relatedPrivileges);

    var request = new RetrieveRequest()
    {
        ColumnSet = new ColumnSet(true),
        RelatedEntitiesQuery = relationshipQueryCollection,
        Target = new EntityReference("role", roleId)
    };

    var response = (RetrieveResponse)service.Execute(request);

    return response.Entity.RelatedEntities[roleprivileges_association];
}

Pour plus d’informations : Extraire avec des lignes associées.

Voir aussi

Plug-ins

Notes

Pouvez-vous nous indiquer vos préférences de langue pour la documentation ? Répondez à un court questionnaire. (veuillez noter que ce questionnaire est en anglais)

Le questionnaire vous prendra environ sept minutes. Aucune donnée personnelle n’est collectée (déclaration de confidentialité).