Partager via


Procédure pas à pas pour les revendications : écriture de fournisseurs de revendications pour SharePoint 2010

Résumé : découvrez comment écrire un fournisseur de revendications pour augmenter les revendications et fournir la résolution de noms. L’utilisation de l’authentification par revendications permet d’assigner des droits basés sur des revendications sans savoir qui est un utilisateur ni comment il est authentifié. Il vous suffit de connaître les attributs de l’utilisateur.

Dernière modification : jeudi 31 mai 2012

S’applique à : Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Dans cet article
Vue d’ensemble des fournisseurs de revendications
Partie 1 : augmentation des revendications et inscription de votre fournisseur
Partie 2 : ajout de la prise en charge des nœuds de la hiérarchie
Partie 3 : recherche dans les revendications
Partie 4 : prise en charge de la résolution de noms
Conclusion
Ressources supplémentaires

Auteur :  Steve Peschka, Microsoft Corporation

Contenu

  • Vue d’ensemble des fournisseurs de revendications

  • Partie 1 : augmentation des revendications et inscription de votre fournisseur

  • Partie 2 : ajout de la prise en charge des nœuds de la hiérarchie

  • Partie 3 : recherche dans les revendications

  • Partie 4 : prise en charge de la résolution de noms

  • Conclusion

  • Ressources supplémentaires

Cliquez pour obtenir le code  Télécharger le code : SqlClaimsProvider_MSDNExample.zip(éventuellement en anglais)

Vue d’ensemble des fournisseurs de revendications

Un fournisseur de demandes dans Microsoft SharePoint 2010 émet les revendications et les inclut dans des jetons de sécurité, autrement dit dans le jeton de l’utilisateur. Lorsqu’un utilisateur se connecte à Microsoft SharePoint Foundation 2010 ou à Microsoft SharePoint Server 2010, le jeton de l’utilisateur est validé, puis utilisé pour la connexion à SharePoint.

Un fournisseur de demandes dans SharePoint 2010 est utilisé essentiellement pour les deux raisons suivantes :

  • pour augmenter les revendications ;

  • pour fournir la résolution de noms.

L’augmentation des revendications fait partie d’un processus qui intervient après votre connexion à un site d’authentification par revendications. Il est important de noter que les opérations suivantes peuvent fonctionner avec l’authentification par revendications dans SharePoint 2010 :

  • revendications Windows (lorsque vous vous connectez avec le protocole NTLM ou Kerberos) ;

  • revendications d’authentification basées sur des formulaires (lorsque vous utilisez un fournisseur d’appartenances et de rôles ASP.NET) ;

  • revendications SAM (Security Assertions Markup Language), lorsque vous vous connectez en utilisant un service de jeton de sécurité (STS), tel que Services ADFS (Active Directory Federation Services) 2.0).

À l’issue de la connexion, tous les fournisseurs de revendications enregistrés pour cette application Web sont déclenchés. Lorsque les fournisseurs de revendications sont déclenchés, ils peuvent ajouter des revendications qui n’étaient pas fournies lors de la connexion. Imaginons que vous vous soyez connecté en utilisant l’authentification Windows, mais que nous souhaitions accorder une revendication supplémentaire qui peut être utilisée pour accéder à un système SAP. C’est là qu’intervient l’augmentation des revendications.

La résolution de noms comprend deux parties : le contrôle du sélecteur de personnes et le contrôle à taper. Lorsque vous souhaitez permettre aux utilisateurs de rechercher des revendications et de trouver vos revendications, un fournisseur de demandes vous aide en utilisant le sélecteur de personnes. Le contrôle à taper permet de taper un nom d’utilisateur ou une revendication, puis de cliquer sur le bouton de résolution. Votre fournisseur de demandes peut examiner cette entrée et déterminer sa validité. Le cas échéant, le fournisseur de demandes fera « de son mieux » pour la résoudre.

Après avoir évoqué en termes abstraits ce qu’un fournisseur de demandes pouvait faire, examinons le scénario que nous utiliserons pour créer un fournisseur de demandes personnalisé. Dans notre scénario, nous voulons affecter des droits dans notre collection de sites, basés sur l’équipe de basketball favorite d’une personne. Il s’agit de l’une des riches fonctionnalités de l’authentification par revendications avec lesquelles vous devez vous familiariser ; nous ne nous soucions pas vraiment de savoir qui est l’utilisateur ni comment il est authentifié sur le site, nous nous occupons uniquement d’un attribut de l’utilisateur : son équipe favorite.

Pour notre application Web, j’ai activé les revendications Windows et l’authentification basée sur les formulaires. J’utilise le fournisseur d’appartenances et de rôles SQL standard pour les utilisateurs de l’authentification basée sur les formulaires et j’ai prérempli ma liste de comptes d’authentification basés sur les formulaires avec les utilisateurs user1 à user50. Pour simplifier le scénario, l’équipe favorite d’une personne est déterminée comme suit :

  • L’équipe favorite de tous les utilisateurs Windows est Consolidated Messenger.

  • Pour les utilisateurs de l’authentification basée sur les formulaires :

    • L’équipe favorite des utilisateurs user1 à user15 est Consolidated Messenger.

    • L’équipe favorite des utilisateurs user116 à user130 est Wingtip Toys.

    • L’équipe favorite des utilisateurs user131 à user150 est Tailspin Toys.

Partie 1 : augmentation des revendications et inscription de votre fournisseur

Notre première action consistera à augmenter les revendications. Comme décrit précédemment, lorsqu’une personne a été authentifiée, notre fournisseur de revendications se déclenche. Nous utilisons les règles que j’ai définies précédemment pour ajouter une revendication (quelle est leur équipe de basketball favorite) au jeton utilisateur.

Procédez comme suit pour écrire un fournisseur de revendications. L’exemple utilise Microsoft Visual Studio 2010 pour créer une application de bibliothèque de classes.

Étape 1: ajouter des références

Commencez par ajouter des références à Microsoft.SharePoint et Microsoft.IdentityModel. Je suppose que vous pouvez trouver Microsoft.SharePoint.dll dans votre installation SharePoint. Microsoft.IdentityModel.dll est installé dans le cadre de la fondation d’identité Windows. Voici le chemin d’accès complet à Microsoft.IdentityModel.dll dans mon installation.

<drive>:\Program Files\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\Microsoft.IdentityModel.dll

Étape 2 : ajout à l’aide de l’héritage de la classe et des instructions

Maintenant que nous disposons de nos références, nous devons ajouter nos instructions using et définir la classe de base dont notre classe hérite. Dans cet exemple, nous utilisons les instructions using suivantes.

using Microsoft.SharePoint.Diagnostics;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.WebControls;

Notre classe doit hériter de la classe de base SPClaimProvider. Le code suivant montre que notre classe figure au début. Ne vous laissez pas troubler par le nom SqlClaimsProvider : au début, j’avais décidé de l’écrire pour qu’il fonctionne uniquement avec le fournisseur de rôles et d’appartenances SQL, mais j’ai finalement décidé de le faire fonctionner également avec Windows.

namespace SqlClaimsProvider
{
    public class SqlClaims : SPClaimProvider
    {

        public SqlClaims(string displayName)
            : base(displayName)
        {
        }
    }
}

Étape 3 : ajout de l’implémentation requise

Au lieu de parcourir toutes les interfaces que vous devez implémenter, vous pouvez vous arrêter sur le nom SPClaimProvider dans le code précédent, cliquer sur la flèche vers le bas située sous le bouton S, puis sélectionner la commande Implémenter la classe abstraite « SPClaimProvider ».

Étape 4 : implémentation de la fonctionnalité incluse dans le fournisseur

Après avoir implémenté la classe abstraite, vous devez implémenter cinq propriétés dans la classe SPClaimProvider, indépendamment de ce que vous ferez : Name, SupportsEntityInformation, SupportsHierarchy, SupportsResolve et SupportsSearch.

Commencez par les propriétés Supports*. Si vous procédez uniquement à l’augmentation des revendications, les informations sur l’entité sont les seules à prendre en charge. Voici un aperçu de la liste des propriétés dans ma classe.

public override bool SupportsEntityInformation
{
      get 
      { 
            return true; 
      }
}

public override bool SupportsHierarchy
{
      get 
      { 
            return false; 
      }
}

public override bool SupportsResolve
{
      get 
      { 
            return false; 
      }
}

public override bool SupportsSearch
{
      get 
      { 
            return false; 
      }
}

Implémentez ensuite la prise en charge de la propriété Name. En général, vous souhaitez prendre en charge un nom d’affichage et un nom « interne » par lequel votre fournisseur peut être référencé.

Dans ce cas, j’utilise les propriétés statiques internes afin de pouvoir les partager avec une autre classe que j’ajouterai ultérieurement dans le projet. Voici un aperçu de mon implémentation de la propriété Name.

internal static string ProviderDisplayName
{
      get
      {
            return "Basketball Teams";
      }
}


internal static string ProviderInternalName
{
      get
      {
            return "BasketballTeamProvider";
      }
}


public override string Name
{
      get
      {
            return ProviderInternalName;
      }
}

À ce stade, nous avons terminé l’implémentation de base. Passons à des choses plus intéressantes. Pour commencer, je configure un tableau à utiliser dans notre fournisseur de demandes pour les équipes. Il est ajouté en haut de la classe, comme suit.

// Teams that we are using.
private string[] ourTeams = new string[] { "Consolidated Messenger", "Wingtip Toys", "Tailspin Toys " };

Ensuite, nous devons implémenter le cœur de notre fournisseur de demandes. Pour augmenter les revendications, nous ajoutons le code d’implémentation pour la méthode FillClaimsForEntity, la méthode FillClaimTypes et la méthode FillClaimValueTypes dans la classe SPClaimProvider.

Créons d’abord des fonctions d’assistance simples, que nous appellerons via la création de notre fournisseur de demandes. Ces fonctions d’assistance définissent le ClaimType, qui est, au fond, l’espace de noms ou l’identificateur de la revendication, et le ClaimValueType, tel que string ou int.

Voici les deux fonctions d’assistance qui opéreront cela pour nous.

private static string SqlClaimType
{
      get
      {
            return "http://schema.steve.local/teams";
      }
}

private static string SqlClaimValueType
{
      get
      {
            return Microsoft.IdentityModel.Claims.ClaimValueTypes.String;
      }
}

À ce stade, vous pouvez conclure de cela que si notre fournisseur de revendications fonctionne, nous ajouterons une revendication nommée http://schema.steve.local/teams et que la valeur dans cette revendication est une chaîne.

D’après le code et les informations précédentes, nous savons que la valeur sera Consolidated Messenger, Wingtip Toys ou Tailspin Toys. En ce qui concerne le nom de la revendication, aucune règle n’impose ce à quoi il doit ressembler. Nous adoptons généralement le format schemas.SomeCompanyName.com/ClaimName. Dans le cas présent, mon domaine est steve.local. J’ai donc utilisé schemas.steve.local et teams est la propriété que cette revendication devra suivre.

L’ajout de cette revendication se fait à l’étape suivante, dans la méthode FillClaimsForEntity de la classe SPClaimProvider, comme illustré dans le code suivant.

protected override void FillClaimsForEntity(Uri context, SPClaim entity, 
      List<SPClaim> claims)
{
if (entity == null)
      throw new ArgumentNullException("entity");

if (claims == null)
      throw new ArgumentNullException("claims");

// Determine who the user is, so that we know what team to add to their claim
// entity. The value from the input parameter contains the name of the 
// authenticated user. For a SQL forms-based authentication user, it looks similar to
// 0#.f|sqlmembership|user1; for a Windows claims user it looks similar 
// to 0#.w|steve\\wilmaf.
// I will skip some uninteresting code here, to look at that name and determine
// whether it is a forms-based authentication user or a Windows user, and if it is a forms-based authentication user, 
// determine what the number part of the name is that follows "user".

string team = string.Empty;
int userID = 0;
            
// After the uninteresting code, "userID" will equal -1 if it is a Windows user.
// If it is a forms-based authentication user, it will contain the number that follows "user".
            
// Determine what the user's favorite team is.
if (userID > 0)
{
      // Plug in the appropriate team.
      if (userID > 30)
            team = ourTeams[2];
      else if (userID > 15)
            team = ourTeams[1];
      else
            team = ourTeams[0];
}
else
      team = ourTeams[1];  
      // If they are not one of our forms-based authentication users, 
      // make their favorite team Wingtip Toys.
      
// Add the claim.
claims.Add(CreateClaim(SqlClaimType, team, SqlClaimValueType));
}

La partie essentielle de cette méthode est la dernière ligne de code. Nous prenons le paramètre d’entrée claims, qui est une liste d’objets SPClaim et nous créons une revendication en utilisant la méthode d’assistance CreateClaim.

ConseilConseil

Je vous encourage vivement à utiliser les méthodes d’assistance dès que possible. Leur rôle ne s’arrête généralement pas à utiliser les constructeurs par défaut et vous pourrez constater globalement qu’ils permettent un meilleur fonctionnement.

Enfin, lorsque nous créons la revendication, nous utilisons les deux méthodes d’assistance décrites précédemment : la méthode SqlClaimType et la méthode SqlClaimValueType.

À ce stade, nous avons réalisé la partie la plus complexe de ce code, et il nous reste à fournir l’implémentation de deux méthodes supplémentaires : FillClaimTypes et FillClaimValueTypes. La création de ces méthodes est simple, car nous nous appuyons sur nos méthodes d’assistance. Voici un aperçu de leur implémentation.

protected override void FillClaimTypes(List<string> claimTypes)
{
      if (claimTypes == null)
            throw new ArgumentNullException("claimTypes");

      // Add our claim type.
      claimTypes.Add(SqlClaimType);
}

protected override void FillClaimValueTypes(List<string> claimValueTypes)
{
      if (claimValueTypes == null)
            throw new ArgumentNullException("claimValueTypes");

      // Add our claim value type.
      claimValueTypes.Add(SqlClaimValueType);
}

J’imagine que tout cela est assez simple et je ne vais donc pas m’attarder sur le sujet.

Nous avons terminé l’implémentation de base d’un fournisseur de demandes, qui devrait augmenter les revendications pour nous. Maintenant, comment l’utiliser ? La meilleure méthode consiste à utiliser un récepteur de fonctionnalités de revendications.

Étape 5 : création du récepteur de fonctionnalités de fournisseur de revendications

Démarrons cette étape en ajoutant une classe au projet. Cette classe héritera de la classe de base SPClaimProviderFeatureReceiver. Son implémentation est simple. J’ai donc copié tout le code du fichier de code d’exemple dans l’exemple suivant.

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.Diagnostics;


namespace SqlClaimsProvider
{
    public class SqlClaimsReceiver : SPClaimProviderFeatureReceiver
    {

        private void 
              ExecBaseFeatureActivated(
              Microsoft.SharePoint.SPFeatureReceiverProperties properties)
        {
            // Wrapper function for base FeatureActivated. Used because base
            // keyword can lead to unverifiable code inside lambda expression.
            base.FeatureActivated(properties);
        }

        public override string ClaimProviderAssembly
        {
            get 
            {
                return typeof(SqlClaims).Assembly.FullName;
            }
        }

        public override string ClaimProviderDescription
        {
            get 
            { 
                return "A sample provider written by Steve Peschka"; 
            }
        }

        public override string ClaimProviderDisplayName
        {
            get 
            {
                  // This is where we reuse that internal static property.
                return SqlClaims.ProviderDisplayName; 
            }
        }

        public override string ClaimProviderType
        {
            get 
            {
                return typeof(SqlClaims).FullName; 
            }
        }

        public override void FeatureActivated(
              SPFeatureReceiverProperties properties)
        {
            ExecBaseFeatureActivated(properties);
        }
    }
}

Il est important de souligner les points suivants :

  • Les propriétés ClaimProviderAssembly et ClaimProviderType de la classe SPClaimProviderFeatureReceiver utilisent tout simplement les propriétés types de la classe fournisseur de demandes personnalisée que nous avons écrite.

  • ClaimProviderDisplayName utilise la propriété statique interne que nous avons créée sur notre classe fournisseur de demandes. Nous avons créé la propriété de façon à pouvoir la réutiliser dans notre récepteur de fonctionnalités de revendications.

  • L’événement FeatureActivated appelle notre méthode interne spéciale pour activer les propriétés.

Étape 6 : compilation de l’assembly et ajout au Global Assembly Cache

J’ai voulu que cette étape soit manuelle, mais rien ne vous empêche d’utiliser un package de solution. Dans le présent scénario, j’effectue toutes les opérations sur un serveur en mode développement. Le procédé aurait été légèrement différent si j’avais été prêt à le distribuer sur ma batterie de serveurs.

Pour le moment, vérifiez que votre assembly est fortement nommé, puis compilez-le. Pour procéder, utilisez la méthode de votre choix pour ajouter l’assembly au Global Assembly Cache (personnellement, j’utilise un événement post-build et l’outil Global Assembly Cache gacutil.exe). Nous sommes maintenant prêts à créer et à déployer notre fonctionnalité.

Étape 7 : création et déploiement de la fonctionnalité de fournisseur de revendications

Cette étape ne comporte rien de propre aux fournisseurs de revendications. Nous créons et nous déployons une fonctionnalité SharePoint standard. Les principes essentiels de la création et du déploiement d’une fonctionnalité fournisseur de demandes n’entrent pas dans le cadre de cet article. Pour vous en donner un aperçu, j’ai recopié le code XML suivant de mon fichier feature.xml.

Notes

Pour plus d’informations sur les fonctions d’installation et de désinstallation, voir Installation ou désinstallation de fonctionnalités.

<Feature   Id="3E864B5C-D855-43e4-B41A-6E054C6C0352" 
           Title="Sql Claims Provider Feature" 
           Scope="Farm" 
           ReceiverAssembly="SqlClaimsProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=eaf1ba21464322ae" 
           ReceiverClass="SqlClaimsProvider.SqlClaimsReceiver" 
           xmlns="https://schemas.microsoft.com/sharepoint/" />

En prenant mon fichier feature.xml comme référence, j’ai créé un répertoire nommé SqlClaimsProvider dans mon dossier Features et j’y ai installé ma fonctionnalité. Comme il s’agit d’une fonctionnalité qui porte sur la batterie, elle est automatiquement activée. Voici la commande qui permet d’effectuer cette opération dans Windows PowerShell.

install-spfeature -path SqlClaimsProvider

À ce stade, tout est en place et nous pouvons tester le fournisseur de revendications.

Étape 8 : connexion au site et test

Pour cette dernière étape, j’utilise mon application Web, décrite au début du présent article. Elle prend en charge les revendications d’authentification Windows et basées sur les formulaires.

Notes

Pour plus d’informations sur la connexion à SharePoint, voir Revendications entrantes : connexion à SharePoint.

Pour confirmer que mes revendications sont bien augmentées, j’ai créé un composant WebPart qui les affiche toutes. Je vous montrerai des captures d’écran qui confirment que l’augmentation des validations fonctionne.

Mais, pour commencer, je me connecte au site en utilisant les informations d’identification Windows. Souvenez-vous de notre code précédent : Wingtip Toys doit toujours être affecté comme équipe favorite d’un utilisateur Windows. La figure 1 en donne un aperçu pour l’utilisateur Windows.

Figure 1. Augmentation des demandes pour utilisateur Windows

Augmentation des demandes pour utilisateur Windows

La figure 2 en donne un aperçu pour un utilisateur authentifié basé sur des formulaires.

Figure 2. Augmentation des demandes pour utilisateur authentifié basé sur des formulaires

Augmentation des demandes pour l’authentification basée sur des formulaires

Tout va bien, l’augmentation des revendications fonctionne ! Dans la partie 2, j’explique comment commencer à utiliser le sélecteur de personnes et je décris la prise en charge et l’ajout d’une hiérarchie au sélecteur de personnes.

Partie 2 : ajout de la prise en charge des nœuds de la hiérarchie

Dans la Partie 1 : augmentation des revendications et inscription de votre fournisseur, j’ai expliqué comment créer un fournisseur de demandes personnalisé et comment augmenter les revendications. Dans la partie 2, j’explique une méthode simple pour ajouter une hiérarchie au contrôle Sélecteur de personnes. En soi, cela n’est pas très intéressant, mais, dans la partie 3, vous verrez comment il est possible de l’utiliser.

Pour continuer, revenons à la classe que nous avons créée pour la partie 1 et occupons-nous d’une propriété et d’une méthode de la classe SPClaimProvider : la propriété SupportsHierarchy et la méthode FillHierarchy.

Nous voulons que la propriété SupportsHierarchy retourne true pour que SharePoint sache que nous pouvons remplir une hiérarchie, comme illustré dans l’extrait de code suivant.

public override bool SupportsHierarchy
{
      get 
      { 
            return true; 
      }
}

Après avoir paramétré la propriété SupportsHierarchy sur true, notre méthode FillHierarchy sera appelée par SharePoint à l’affichage du sélecteur de personnes.

Lorsque nous ajoutons un nœud à la hiérarchie, nous devons fournir un nom d’affichage et un identificateur de nœud (ID). Pour ce faire, et pour que cela corresponde aux équipes de basketball favorites que nous utilisons, j’ai créé des tableaux d’assistance simples pour suivre les noms d’étiquettes et les ID. Voici un aperçu du code. Le tableau des noms d’équipes utilisés pour nos équipes favorites y figure également.

// Teams that we are using.
private string[] ourTeams = new string[] { "Consolidated Messenger", "Wingtip Toys", "Tailspin Toys " };

// Keys for our People Picker hierarchy.
private string[] teamKeys = new string[] { "empUS", "empEMEA", "empASIA" };

// Labels for our nodes in the People Picker.
private string[] teamLabels = new string[] { "US Teams", "European Teams", "Asian Teams" };

Maintenant que nous connaissons nos clés et nos étiquettes, je vais vous montrer la méthode FillHierarchy que j’utilise pour ajouter les nœuds lorsque le sélecteur est affiché. Je fais cela uniquement à des fins de démonstration, car aucune raison fonctionnelle ne justifie cela dans le cadre de notre scénario.

Il est important de noter qu’une revendication peut servir à fournir presque tous les éléments de sécurité dans un site SharePoint, à l’exception d’un administrateur de collection de sites. Heureusement, nous disposons d’un indice en cas de recherche d’un administrateur de collection de sites. Lorsque cela se produit, le tableau entityTypes a un élément, Users. Dans tous les autres cas, vous voyez généralement au moins six éléments dans le tableau entityTypes. Nous ajoutons donc un contrôle spécifique lorsque nous renseignons la hiérarchie, car nous ne souhaitons pas ajouter une hiérarchie que nous n’utiliserons jamais.

protected override void FillHierarchy(Uri context, string[] entityTypes,
      string hierarchyNodeID, int numberOfLevels,
      Microsoft.SharePoint.WebControls.SPProviderHierarchyTree hierarchy)
{                        

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// Check to see whether the hierarchyNodeID is null; it is when the control 
// is first loaded, but if a user clicks on one of the nodes, it will return
// the key of the node that was clicked. This lets you build out a 
// hierarchy as a user clicks something, instead of all at once. So I 
// wrote the code for that scenario, but I am not using it in that way.  
// Which means that I could have just as easily used an 
// if (hierarchyNodeID == null) in this particular implementation, instead
// of a switch statement.
switch (hierarchyNodeID)
{
      case null:
            // When it first loads, add all our nodes.
            hierarchy.AddChild(new 
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName, 
                  teamLabels[0], 
                  teamKeys[0], 
                  true));

            hierarchy.AddChild(new
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName,
                  teamLabels[1],
                  teamKeys[1],
                  true));

            hierarchy.AddChild(new
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName,
                  teamLabels[2],
                  teamKeys[2],
                  true));
            break;
      default:
            break;
} 
}

Il me reste à vérifier si hierarchyNodeID est nul, ce qui est toujours le cas au premier chargement du contrôle. Le cas échéant, j’ajoute mes nœuds à l’arborescence dans le volet gauche. Pour que le code fonctionne, je recompile mon assembly, je l’ajoute au Global Assembly Cache, et je procède à un IISRESET. Je peux ensuite atteindre le site et essayer de modifier les autorisations pour lancer le sélecteur de personnes. La figure 3 illustre le sélecteur de personnes après l’implémentation de ce code.

Figure 3. Sélecteur de personnes avec nœud hiérarchique

Sélecteur de personnes avec nœud hiérarchique

Là aussi, une chose importante est à noter. Si vous suivez attentivement, vous vous demandez peut-être pourquoi le sélecteur de personnes affiche Steve’s SQL Claims Provider comme nom de fournisseur de demandes et non la valeur de la propriété Name vue dans le code, Basketball Teams. Pour tout vous dire, je suis feignant... Ce que vous voyez est le nom d’origine de mon fournisseur de demandes. Lorsque j’ai étoffé le scénario, j’ai décidé de changer ce nom, mais je n’ai pas procédé à sa mise à jour dans la liste fournisseur de demandes. Ceci explique cela.

Dans la partie 3, nous analysons comment activer la recherche des revendications dans le sélecteur de personnes en utilisant votre fournisseur de demandes personnalisé.

Partie 3 : recherche dans les revendications

Dans les deux premières parties du présent article, nous avons vu comment créer un fournisseur de demandes personnalisé, comment augmenter les revendications et enregistrer le fournisseur et comment ajouter une hiérarchie au sélecteur de personnes. Dans la partie 3, je décris comment implémenter la recherche dans nos revendications dans le sélecteur de personnes avec notre fournisseur de demandes personnalisé. Sans moyen de sélectionner notre revendication personnalisée, impossible de fournir les autorisations dans le site en fonction de notre équipe de basketball favorite.

Arrêtons-nous un instant sur ce point, qui n’est pas toujours évident à comprendre. Fournir des autorisations en fonction d’un attribut de l’utilisateur plutôt qu’en fonction de qui est l’utilisateur ouvre de nombreuses possibilités. Cela peut signifier, comme dans notre scénario, que peu m’importe qui vous êtes. Peu m’importe comment vous vous êtes connecté. Peu m’importe que vous soyez un utilisateur Windows ou un utilisateur de l’authentification basée sur les formulaires.

Tout ce qui m’importe est de savoir qui est votre équipe de basketball favorite. Il s’agit d’un problème classique de Microsoft Office SharePoint Server 2007, toujours d’actualité dans SharePoint 2010. Lorsque je travaille, je me connecte à mon site SharePoint avec mes informations d’identification Windows, Steve Peschka. Mais chez moi, je me connecte au site via notre extranet et je dois utiliser l’authentification basée sur les formulaires.

Pour notre scénario, supposons que je sois un utilisateur de l’authentification basée sur les formulaires, user1. Quel est le problème ? Pour SharePoint, il s’agit de deux utilisateurs. Il est impossible dans SharePoint Server 2007 ou dans SharePoint 2010 de mapper les utilisateurs d’une façon ou d’une autre pour dire que « l’utilisateur Windows Steve Peschka et l’utilisateur de l’authentification basée sur les formulaires user1 sont les mêmes personnes ».

Devinez quoi ? Désormais, nous n’avons plus à nous soucier de cela. Pourquoi ? Parce que nous n’affectons plus les autorisations en fonction des personnes, mais en fonction de leur équipe de basketball favorite. Le scénario que j’ai mis en place est simple. Mais vous pouvez imaginer, pour des métadonnées d’entreprise associées à une personne, que le fournisseur de demandes fasse une recherche dans un autre système pour déterminer toutes les identités utilisées par une personne - authentification Windows, authentification basée sur les formulaires, SAP, CRM, etc. - et soit à même de mapper un autre identificateur ou des revendications à cette identité. Ces revendications servent ensuite à accorder des accès à des ressources.

Souhaitez-vous un système d’authentification unique entre vos différentes applications Web ? Là encore, user1 dans l’application Web 1 est différent de user1 dans l’application Web 2. Peu importe ! Tant que j’utilise ma revendication par équipe de basketball favorite, cette personne peut passer sans heurt d’une application Web à une autre, car nous l’augmentons chaque fois qu’elle s’authentifie. Je ne vous dirais pas que ce système est parfait, il ne l’est pas. Mais il est probablement plus proche de la perfection que les modèles de sécurité précédents.

Bien, maintenant que ce point est clair, abordons le sujet de la prise en charge de la recherche dans le sélecteur de personnes. Pour que notre fournisseur de demandes personnalisé prenne en charge la recherche, nous devons ajouter la prise en charge des propriétés et des méthodes suivantes de la classe SPClaimProvider : SupportsSearch, SupportsResolve, FillSearch, FillResolve (la surcharge avec un paramètre d’entrée SPClaim), FillSchema et FillEntityTypes.

Commençons par analyser les propriétés, qui devraient être simples à ce stade, comme illustré dans le code suivant.

public override bool SupportsSearch
{
      get 
      { 
            return true; 
      }
}

public override bool SupportsResolve
{
      get 
      { 
            return true; 
      }
}

La méthode FillSearch est probablement la plus intéressante pour vous. Examinons-la dans le code suivant.

protected override void FillSearch(Uri context, string[] entityTypes, 
      string searchPattern, string hierarchyNodeID, int maxCount,
      Microsoft.SharePoint.WebControls.SPProviderHierarchyTree searchTree)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// The counter to track what node we are in; it will be used to call into
// our helper arrays that were covered in part 1 and part 2 of this article.
int teamNode = -1;

// NOTE: If we were not using hierarchies in the People Picker, we would
// probably use a list of PickerEntity instances so that we could
// add them all to the People Picker in one call. I have stubbed it out
// here for demonstration purposes so you can see how you 
// would do it. 
// Picker entities that we will add if we find something.
// List<PickerEntity> matches = new List<PickerEntity>();

// The node where we will place our matches.
Microsoft.SharePoint.WebControls.SPProviderHierarchyNode matchNode = null;

// Look to see whether the value that is typed in matches any of our teams.
foreach (string team in ourTeams)
{
      // Increment team node tracker.
      teamNode += 1;

      // Simple way to do a string comparison to the search criteria.
      // This way, all a person has to type in to find Consolidated Messenger is "b".
      if (team.ToLower().StartsWith(searchPattern.ToLower()))
      {
            // We have a match, create a matching entity.
            // This is a helper method that I will explain later.
            PickerEntity pe = GetPickerEntity(team);

            // If we did not have a hierarchy, we would add it here
            // by using the list described previously.
            // matches.Add(pe);

            // Add the team node where it should be displayed; 
            // ensure that we have not already added a node to the tree
            // for this team's location.
            if (!searchTree.HasChild(teamKeys[teamNode]))
            {
                  // Create the node so that we can show our match in there too.
                  matchNode = new 
                  SPProviderHierarchyNode(SqlClaims.ProviderInternalName,
                  teamLabels[teamNode],
                  teamKeys[teamNode],
                  true);

                  // Add it to the tree.
                  searchTree.AddChild(matchNode);
             }
             else
                  // Get the node for this team.
                  matchNode = searchTree.Children.Where(theNode =>
                  theNode.HierarchyNodeID == teamKeys[teamNode]).First();

            // Add the picker entity to our tree node.
            matchNode.AddEntity(pe);
      }
}

// If we were adding all the matches at once,that is, if we were not using
// a hierarchy, then we would add the list of matches here.
// if (matches.Count > 0)
//    searchTree.AddEntities(matches);
}

Là encore, le code est probablement assez explicite. En substance, l’utilisateur a tapé quelque chose dans le sélecteur de personnes, puis a cliqué sur le bouton de recherche. Notre fournisseur de demandes est appelé, car notre propriété SupportsSearch retourne true. Dans la méthode appelée, FillSearch, nous examinons ce que l’utilisateur a tapé, qui nous est fourni par le paramètre d’entrée searchPattern. Nous examinons l’ensemble des noms d’équipes pour savoir si l’un d’eux commence par la valeur tapée dans la zone de recherche. Le cas échéant, nous créons une nouvelle entité PickerEntity, nous cherchons ou nous créons un nœud de hiérarchie d’arborescence avec l’emplacement de cette équipe, puis nous ajoutons notre entité PickerEntity à ce nœud.

Le code précédent montre que nous utilisons une fonction d’assistance spécifique appelée GetPickerEntity, dans laquelle nous passons le nom d’équipe trouvé. En voici l’illustration dans le code suivant.

private PickerEntity GetPickerEntity(string ClaimValue)
{

// Use the helper function!
PickerEntity pe = CreatePickerEntity();

// Set the claim that is associated with this match.
pe.Claim = CreateClaim(SqlClaimType, ClaimValue, SqlClaimValueType);

// Set the tooltip that is displayed when you pause over the resolved claim.
pe.Description = SqlClaims.ProviderDisplayName + ":" + ClaimValue;

// Set the text that we will display.
pe.DisplayText = ClaimValue;

// Store it here, in the hashtable **
pe.EntityData[PeopleEditorEntityDataKeys.DisplayName] = ClaimValue;

// We plug this in as a role type entity.
pe.EntityType = SPClaimEntityTypes.FormsRole;

// Flag the entry as being resolved.
pe.IsResolved = true;

// This is the first part of the description that shows
// above the matches, like Role: Forms Auth when
// you do an forms-based authentication search and find a matching role.
pe.EntityGroupName = "Favorite Team";

return pe;
}

Ici, nous créons un objet PickerEntity. Comme indiqué par les commentaires de code, la méthode CreatePickerEntity de la classe SPClaimProvider est une autre fonction d’assistance fournie par SharePoint. Je recommande vivement, une nouvelle fois, d’utiliser les fonctions d’assistance dès que possible.

Après avoir créé notre objet PickerEntity, nous devons décrire de quoi il s’agit. Il s’agit ici d’une revendication pour une équipe favorite de basketball. Nous décrivons cela au système comme la création d’une revendication en utilisant la même approche que celle utilisée pour notre code d’augmentation de revendications. Nous avons passé le nom de l’équipe à cette fonction d’assistance pour qu’elle puisse placer l’équipe favorite de la personne dans notre revendication d’équipe favorite. Après cela, nous définissons plusieurs propriétés sur l’objet PickerEntity pour qu’il affiche et se comporte comme d’autres revendications connues pour des revendications Windows ou des revendications d’authentification basées sur des formulaires. Nous retournons ensuite le PickerEntity que nous avons créé.

Toutefois, nous n’avons pas tout à fait terminé. Si nous nous arrêtions ici, nous verrions la revendication dans le sélecteur de personnes et nous pourrions la sélectionner. Lorsque vous cliquez sur le bouton OK pour fermer la boîte de dialogue Sélecteur de personnes, vous devriez voir la revendication dans le contrôle à taper. Mais il devrait être assorti d’un soulignement ondulé en rouge pour indiquer qu’il n’est pas résolu. À ce stade, vous ne devriez pas pouvoir le résoudre.

En réalité, lorsque vous cliquez sur le bouton OK pour fermer la boîte de dialogue du sélecteur de personnes, SharePoint tente d’effectuer un autre appel dans votre fournisseur de demandes vers la méthode FillResolve. Il s’agit d’une méthode surchargée. La méthode appelée lorsque vous fermez la boîte de dialogue Sélecteur de personnes est celle qui contient un paramètre d’entrée SPClaim. Examinons donc l’implémentation de cette méthode, comme illustrée dans le code suivant.

protected override void FillResolve(Uri context, string[] entityTypes, 
      SPClaim resolveInput, 
      List<Microsoft.SharePoint.WebControls.PickerEntity> resolved)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// Same sort of code as in search, to validate that we have a match.
foreach (string team in ourTeams)
{
if (team.ToLower() == resolveInput.Value.ToLower())
{
      // We have a match; create a matching entity with helper method.
      PickerEntity pe = GetPickerEntity(team);

      // Add it to the return list of picker entries.
      resolved.Add(pe);
}
}

La méthode FillResolve est simple. Vous vous souvenez peut-être, d’après la Partie 1 : augmentation des revendications et inscription de votre fournisseur du présent article, que la propriété Value de la classe SPClaim contient la valeur de la revendication. Plusieurs articles ayant pu être sélectionnés dans le sélecteur de personnes, comme nous sommes passés dans une revendication, nous procédons de nouveau à l’énumération via notre liste d’équipes pour savoir si la valeur de la revendication correspond à une valeur de nos équipes. Le cas échéant, nous appelons notre méthode d’assistance pour créer un objet PickerEntity, puis nous l’ajoutons à la liste des instances PickerEntity pour SharePoint. Nous voyons donc une entrée résolue dans le contrôle à taper après notre sélection dans le sélecteur de personnes.

Vous devez implémenter deux autres méthodes : la méthode FillSchema et la méthode FillEntityTypes de la classe de base SPClaimProvider. Dans la méthode FillSchema, nous ajoutons la propriété minimale à utiliser dans le sélecteur de personnes, c’est-à-dire le nom d’affichage. Pour ce faire, nous ajoutons le nom d’affichage au schéma.

Dans la méthode FillEntityTypes, nous voulons retourner le type de revendications utilisé par notre fournisseur de demandes. Dans notre cas, nous avons défini notre type de revendication comme SPClaimEntityTypes.FormsRole dans la méthode GetPickerEntity. J’ai donc ajouté ce rôle à la liste des types d’entités, comme illustré dans le code suivant.

protected override void 
FillSchema(Microsoft.SharePoint.WebControls.SPProviderSchema schema)
{
// Add the schema element that we need at a minimum in our picker node.
schema.AddSchemaElement(new 
      SPSchemaElement(PeopleEditorEntityDataKeys.DisplayName, 
      "Display Name", SPSchemaElementType.Both));
}

protected override void FillEntityTypes(List<string> entityTypes)
{
// Return the type of entity claim that we are using (only one in this case).
entityTypes.Add(SPClaimEntityTypes.FormsRole);
}

La figure 4 illustre le sélecteur de personnes après avoir recherché wingtip.

Figure 4. Recherche dans le sélecteur de personnes

Recherche dans le sélecteur de personnes

La figure 5 illustre le contrôle à taper après l’ajout de notre revendication, après avoir cliqué sur OK.

Figure 5. Affichage du contrôle à taper après ajout d’une revendication

Affichage du contrôle de frappe après ajout d’une demande

Du point de vue du code, nous avons terminé. Mais il est temps de relier cela à la discussion du début de l’article. Nous pouvons désormais fournir des autorisations en fonction de notre équipe de basketball favorite. Dans ce cas, j’ai décidé que les personnes dont l’équipe favorite est Wingtip Toys devraient pouvoir collaborer pour le contenu du site. Dans ce cas, j’ai ajouté cette revendication au groupe Members. La figure 6 illustre cela (ne vous laissez pas dérouter par le nom de la collection de sites, Windows Claims).

Figure 6. Ajout d’une revendication au groupe Members

Ajout d’une demande au groupe de membres

Souvenez-vous de ce que j’ai dit sur le fait de ne plus avoir à se soucier de savoir qui vous êtes ni comment vous vous êtes connecté. Par exemple, je n’ai accordé aucun droit de rôle d’utilisateur Windows, de groupe Windows, d’utilisateur de l’authentification basée sur les formulaires ni d’authentification par formulaire sur le site. J’ai ajouté ma revendication pour Wingtip Toys au groupe Members et ma revendication pour Consolidated Messenger au groupe Visitors.

La figure 7 prouve ce à quoi ma liste de tous les groupes ressemble pour cette collection de sites.

Figure 7. Liste d’autorisations de groupe pour une collection de sites

Liste d’autorisations de groupe pour une collection de sites

J’espère que vous pourrez ainsi vous rendre compte de la puissance de l’authentification basée sur des formulaires et des fournisseurs d’authentification. Dans la dernière partie de cet article, j’explique comment implémenter la prise en charge des personnes qui tapent un nom de revendication dans le contrôle à taper.

Partie 4 : prise en charge de la résolution de noms

Dans les trois premières parties du présent article, nous avons implémenté la plus grande partie de la prise en charge nécessaire pour créer un fournisseur de demandes de bout en bout. Dans cette dernière partie, je décris comment mettre en œuvre la prise en charge de la résolution de noms dans le contrôle à taper.

Pour ajouter la prise en charge de la résolution de noms, nous devons mettre en œuvre la propriété et la méthode suivantes de la classe SPClaimProvider : la propriété SupportsResolve et la méthode FillResolve.

La bonne nouvelle est que j’ai déjà traité l’implémentation de la propriété SupportsResolve et une des surcharges de méthodes FillResolve dans Partie 3 : recherche dans les revendications. Cette section est donc courte. Voici le code permettant d’implémenter l’autre surcharge de la méthode FillResolve qui n’était pas décrite dans « Partie 3 : recherche dans les revendications ».

protected override void FillResolve(Uri context, string[] entityTypes, 
      string resolveInput, 
      List<Microsoft.SharePoint.WebControls.PickerEntity> resolved)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;
 
// Same sort of code as in search, to validate that we have a match.
foreach (string team in ourTeams)
{
      if (team.ToLower() == resolveInput.ToLower())
      {
            // We have a match;, create a matching entity.
            PickerEntity pe = GetPickerEntity(team);

            // Add it to the return list of picker entries.
            resolved.Add(pe);
       }
}
}

Si vous avez tout suivi, ce bout de code est simple. Sinon, relisez Partie 3 : recherche dans les revendications.

Nous avons terminé pour le code. Si je lance le contrôle à taper, que je tape un nom d’équipe, puis que je clique sur le bouton de résolution, les figures suivantes donnent un aperçu du contrôle à taper avant et après la résolution de noms. La figure 8 donne un aperçu du contrôle à taper lorsque vous tapez le nom de l’équipe.

Figure 8. Contrôle à taper avant de cliquer sur le bouton de résolution

Contrôle à taper avant résolution

La figure 9 donne un aperçu du contrôle à taper après avoir cliqué sur le bouton de résolution.

Figure 9. Contrôle à taper après résolution

Contrôle à taper après résolution

Nous avons terminé. J’espère que vous trouverez ces informations utiles pour commencer à développer vos plans d’authentification par revendications.

Conclusion

Vous pouvez utiliser un fournisseur de demandes dans SharePoint 2010 pour augmenter les revendications et fournir la résolution de noms. L’authentification par revendications permet d’affecter des droits basés sur des revendications sans savoir qui est un utilisateur ni comment il est authentifié ; vous avez besoin de connaître uniquement les attributs des utilisateurs. Vous pouvez, par exemple, utiliser des métadonnées d’entreprise associées à une personne et laisser le fournisseur de demandes chercher sur un autre système les différentes identités de cette personne - authentification Windows, authentification basée sur les formulaires, SAP, CRM, etc. -, puis mapper un autre identificateur ou un ensemble de revendications à cette identité. Ces revendications sont ensuite utilisées pour accorder l’accès à des ressources.

Ressources supplémentaires

Pour plus d’informations, consultez les ressources suivantes :