none
Difficultés avec UserProfileManager et SPSecurity RRS feed

  • Question

  • Bonjour,

     

    Après plusieurs jours passés sur ce problème, je m'en remets à vous. Mon code ci-dessous marche sans problème lorsque je suis avec un compte Administrateur, mais m'affiche une erreur 403 Forbidden lorsque je suis avec un compte utilisateur basique.

     

    Code Snippet

    SPSecurity.RunWithElevatedPrivileges(
               delegate()
               {
                    // connect to the root Sharepoint site
                    using (SPSite site = new SPSite("http://sharepoint:80/"))
                    {
                        //ServerContext context = ServerContext.GetContext(site);
                        ServerContext context = ServerContext.GetContext(site);
                        UserProfileManager profilemanager = new UserProfileManager(context);
                       
                        int i = 0;
                        foreach(UserProfile profile in profilemanager)
                        {
                            i++;
                            Label1.Text += " ("+ i +")" + profile["PreferredName"].Value.ToString() +" -- ";
                        }
                    }
               }
           );

     

    Quand je suis connecté en tant qu'admin, ça me liste bien tous les comptes de mon Sharepoint. Par contre quand je me connecte avec un compte utilisateur (j'ai essayé avec plusieurs comptes), ça m'affiche une erreur 403 Forbidden.

     

    Il s'agit donc d'un problème de droits car j'utilise UserProfileManager, mais je ne vois pas pourquoi vu que c'est dans un SPSecurity.RunWithElevatedPrivileges(delegate(){};

     

    En espérant que vous aurez des suggestions,

     

    Merci d'avance

    lundi 21 mai 2007 14:58

Réponses

  • Bonjour,

    Même avec cette solution (qui est très lourde, et qui est plus pour SP2003), ça ne marche qu'avec un compte admin, et c'est toujours Forbidden pour un compte standard.

    C'est vraiment dommage qu'il n'y ait pas de fonctions permettant de lister (juste lister et consulter les donner) tous les utilisateurs...


    Je viens d'ouvrir une nouvelle discussion en essayant avec une autre méthode : lister les personnes d'une Groupe SharePoint. Facile me direz vous, mais comment faire quand il y a des listes de distribution de l'Active Directory ?


    http://forums.microsoft.com/MSDN-FR/ShowPost.aspx?PostID=1782801&SiteID=12


    ++

    mardi 26 juin 2007 09:38

Toutes les réponses

  • Salut,

    Je viens de me rendre compte que mon problème d'authorisation ne survenait QUE si j'ajoutais la masterpage (qui est celle de base de Sharepoint 2007). Ma question est donc maintenant : y a t'il un paramètre à modifier dans la MasterPage ?

     

    Merci d'avance

    mardi 22 mai 2007 16:35
  • peut etre dans le web config non ? un impersonation a true si ce n'est pas deja fait
    vendredi 25 mai 2007 22:38
  • Salut,

    Suite à ta remarque, j'ai lancé une petite recherche sur google pour avoir plus d'infos et je suis tombé sur la page http://www.15seconds.com/issue/040511.htm

    Ca pourrait en effet résoudre mon problème si l'instruction <identity impersonate="true" /> n'est pas déjà présente dans mon web.config


    Réponse lundi quand je serais de  nouveau face à mon SharePoint Wink


    Merci et bon week end
    vendredi 25 mai 2007 23:03
  • Il y est par défaut, il devrait donc s'y trouver, sauf modification du web.config.

     

    Je n'ai pas bien compris l'histoire de la master page.

     

    Sous quelles conditions votre code fonctionne et ne fonctionne-t-il pas ?

    samedi 26 mai 2007 09:58
  • Salut,

    Si c'est par défaut, dans ce cas ça doit déjà être présent.

    Mon problème c'est que mon code ci-dessus fonctionne très bien pour n'importe quel type de profil (administrateur, visualisateur, ...) quand je n'ajoute pas la master page (qui celle par défaut de SharePoint 2007).

    Dès que j'ajoute ma master page, ça ne fonctionne plus qu'avec un compte administrateur. Si je la lance avec un compte non admin, ça m'affiche 403 Forbidden.

    Il m'empeche donc de lancer ma page (qui utilise la fonction userProfileManager) avec n'importe quel compte (admin, visiualisateur, ...) quand j'ajoute la master page à ma page.

    Merci d'avance


    samedi 26 mai 2007 10:52
  • Quand vous dites que le code fonctionne très bien dans vous n'ajoutez pas la master page, ca signifie quoi ? Votre code est dans un user control ? Une webpart ? Directement dans la page ?
    dimanche 27 mai 2007 11:14
  • Bonjour,

    Quand je dis que mon code fonctionne bien, ça signifie qu'il est autorisé à être lancé pour tout type de profil (administrateur, visualisateur, ...) Ca n'affiche donc pas 403  Forbidden.

    Quand ce compte fonctionne, il liste tous les comptes SharePoint (donc toutes les personnes de mon entreprise, mon but étant de réaliser un trombinoscope).

    Ce code est placé directement dans une page .aspx et est déclenché lorsque j'appuie sur un bouton. Est-ce qu’en le plaçant dans un user control ou dans une webpart, ça éviterait ce problème de sécurité ?

    Merci d'avance

    dimanche 27 mai 2007 12:06
  • Essayez de mettre votre code dans une webpart pour voir, c'est bien possible que ca résolve vos pbs.
    lundi 28 mai 2007 10:11
  • Entendu, je vais tester cela dans la semaine.

     

    Merci

    lundi 28 mai 2007 14:38
  • Salut,

     

    Je viens de mettre mon code sous forme de WebPart (appelée Trombinoscope), mais malheureusement ça m'affiche : Le composant WebPart « Trombinoscope » semble poser un problème. Échec de la demande d'autorisation de type 'Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'.

     

    J'ai donc un problème de sécurité Tongue Tied Quelqu'un a t'il déjà rencontré ce problème ?

     

    Merci d'avance

    mercredi 30 mai 2007 12:31
  • Comment avez-vous déployé votre webpart ?

     

    Je suppose que la dll est dans le répertoire bin et que vous êtes au niveau de sécurité "WSS_Minimal" (voire WSS_Medium) dans le Web.config (cherchez le noeud <trust level="WSS_Minimal" />. Changez le en full ou bien installez votre dll dans le GAC.

    mercredi 30 mai 2007 13:18
  • Ah parfait mon problème est enfin résolu. Cette fonction marche maintenant quel que soit le profil (admin ou simple visualisateur), grâce au fait qu'il soit dans une WebPart. Pourquoi ça ne marchait pas dans une page .aspx ?

     

    Merci beaucoup Gat

    mercredi 30 mai 2007 13:45
  • En fait, non, le problème est toujours identique Tongue Tied J'ai été un peu trop rapide dans mes tests... Ca marche qu'avec les profils utilisateurs, et pas avec les autres (ils ont affiché 403 FORBIDDEN).

     

    Voici le code de ma webpart :

    Code Snippet

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Web;

    using System.Security;

    using Microsoft.SharePoint;

    using Microsoft.Office.Server;

    using Microsoft.Office.Server.UserProfiles;

    namespace Trombinoscope

    {

    public class Trombinoscope : System.Web.UI.WebControls.WebParts.WebPart

    {

      protected override void Render(System.Web.UI.HtmlTextWriter writer)

      {

        SPSecurity.RunWithElevatedPrivileges(delegate()

        {

           string displayText = "Début Test : ";

           // connect to the root Sharepoint site

           using (SPSite site = new SPSite("http://sharepoint:80/"))

           {

             ServerContext context = ServerContext.GetContext(site);

             UserProfileManager profilemanager = new UserProfileManager(context);

             int i = 0;

             foreach (UserProfile profile in profilemanager) //il faudrait les stocker dans une SortedList

             {

                i++;

                displayText += " (" + i + ")" + profile["PreferredName"].Value.ToString() + " -- ";

             }

           }

           writer.Write(displayText);

        });

      }

    }

    }

     

    Dans un premier temps, j'avais déployé ma dll dans le dossier bin de mon site et en mettant le trustLevel à Full (<trust level="Full" originUrl="" />), puis après j'ai essayé en mettant cette même .dll dans le GAC. Malheureusement le problème d'authorisation est toujours là...

     

    Je ne comprends pas vraimeent pas, car le fonctionnement est exactement pareil que sur le site : http://www.sharepointblogs.com/berton/archive/2007/03/27/un-webpart-qui-afficha-la-liste-des-membres-et-la-pr-sence-lcs-mocs.aspx

     

    En espérant que vosu ayez une idée

     

    mercredi 30 mai 2007 15:26
  • Salut,

     

    Après avoir réalisé une nouvelle série de tests, je viens de trouver précisément où ça bloque. C'est seulement lorsque je fais un foreach sur mon UserProfileManager :


    Code Snippet

    UserProfileManager profilemanager = new UserProfileManager(context);


    foreach(UserProfile profile in profilemanager)
    {

     

    }

     

    J'ai essayé avec IEnumerator, mais le problème reste identique : page 403 FORBIDDEN.

     

    Merci d'avance

     

     

     

    jeudi 31 mai 2007 12:52
  • Je viens de trouver la réponse à mon problème sur le site http://msd2d.com/Content/Tip_viewitem_03NoAuth.aspx?section=Sharepoint&id=1A7E24F2-DCD5-44BF-8EE9-89FEB9BDFE48

     

    En fait, on ne peut pas utiliser IEnumerator de UserProfileManager qu'avec un profil Administrateur, et ce pour des questions de sécurité (sinon n'importe quelques membres pour éditer les informations de tout le monde)... Si ce n'est pas possible avec un IEnumerator, il en est bien entendu de même avec un foreach...

     

    Par conséquent, comment peut-on lister tous les comptes SharePoint de son entreprise ? Il n'y a pas de moyen plus simple que d'aller dans la base SQL (quelqu'un sait-il dans quelle table et s'il y aurait un exemple ?) ??

     

    Merci d'avance

     

     

    jeudi 31 mai 2007 14:03
  • C'est une des limites par sécurité du RunPrivileges.

     

    L'idée serait d'utiliser de l'execution par Token avec un vrai compte admin et non le service account

     

    http://www.sharepointblogs.com/ssa/archive/2006/11/14/adding-a-document-library-and-users-using-impersonation.aspx

    http://www.sharepoint-tips.com/2007/03/impersonation-in-event-handlers.html

     

    Bon courage avec les SPUserToken

     

     

    vendredi 1 juin 2007 10:44
  • Merci pour ce conseil, je teste cela dès demain
    dimanche 3 juin 2007 16:19
  • Comme promis, je viens de tester avec les UserToken. Voici mon code :

    Code Snippet

    protected override void Render(System.Web.UI.HtmlTextWriter _output)
    {
        try
        {
            SPSite site = new SPSite("http://sharepoint");
            SPWeb web = site.OpenWeb();
            SPUser user = web.Users["sharepoint\\administrateur"];
            SPUserToken token = user.UserToken;

            SPSite impSite = new SPSite("http://sharepoint", token);
            if (impSite.Impersonating)
            {
                _output.Write("User impersonation OK!");
                UserProfileManager profileManager2 = new UserProfileManager();
                _output.Write("profileManager2 = " + profileManager2.Count + "<br />");

            }
            else
            {
                _output.Write("User impersonation failed!");
            }
        }

        catch (Exception ex)
        {
            _output.Write(ex.Source + " - " + ex.Message);
        }
    }


    Malheureusement ça ne marche toujours pas quand je teste avec un compte utilisateur standard. Ca m'affiche le message suivant :
    User impersonation OK! Microsoft.Office.Server - Accès refusé : seul un administrateur peut récupérer le nombre d'utilisateurs.

    Bien entendu ça marche lorsque je le lance la page connecté sous le profil utilisateur...

    Bizarre tout de même alors que l'impersonalisation semble bien s'exécuter...

    En espérant que vous ayez des conseils,
    Merci
    lundi 4 juin 2007 09:33
  • I get the same error: "403 Forbidden".  

     

    UserProfileManager profilemanager = new UserProfileManager(context);


    foreach(UserProfile profile in profilemanager)   // 403 error right here!
    {

     

    }

     

    (It works for an administrator but not for regular user).  Sorry about the English Smile

    vendredi 8 juin 2007 02:01
  • Rahhh ca deviens tordu la ....

     

    Faudrais investiguer plus loin mais la je ne vois pas, et je suis en plus dans une periode chargé ...

     

    Ah ce niveau la, faudrais remonter au support MS...

     

    Tenez moi au courant

    vendredi 8 juin 2007 09:12
  • Bonjour,

     

    j'ai exactement le même pb :

     

    Le serveur n'a pas pu traiter la demande. ---> Pour pouvoir exécuter cette opération, vous devez gérer vos données personnelles ou disposer des privilèges d'administrateur.

     

    Comment contourner ce pb ?

    Merci beaucoup!

    lundi 11 juin 2007 15:02
  • Bonsoir,

    Malheureusement ce problème persiste Etant pas mal occupé en ce moment, je n'ai pas eu le temps de contacté le support MS comme le conseiller Renaud. Si jamais quelqu'un a le temps...

    A bientôt
    lundi 11 juin 2007 19:59
  •  

     Bonjour,

     

    j'ai finalement trouvé une solution à mon problème, ce n'est pas forcèment très classe mais ça marche Smile

     

    la manip consiste à s'impersonnifier avec un compte admin, puis de lister les utilisateurs en passant par le webservice Userprofileservice (http://localhost/_vti_bin/userprofileservice.asmx)

    L'inconvénient est le nombre important de requêtes envoyées au webservice

     

    du coup, le résultat est mis en cache...

    voilà si qqu'un trouve une meilleure solution, je suis preneur !

    ++

     

     

    Code Snippet

    #region util pour impresonnation
            public const int LOGON32_LOGON_INTERACTIVE = 2;
            public const int LOGON32_PROVIDER_DEFAULT = 0;
            WindowsImpersonationContext impersonationContext;
            [DllImport("advapi32.dll")]
            public static extern int LogonUserA(String lpszUserName,
                    String lpszDomain,
                    String lpszPassword,
                    int dwLogonType,
                    int dwLogonProvider,
                    ref IntPtr phToken);
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int DuplicateToken(IntPtr hToken,
                    int impersonationLevel,
                    ref IntPtr hNewToken);
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool RevertToSelf();
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern bool CloseHandle(IntPtr handle);

            public bool ImpersonateValidUser(String userName, String domain, String password)
            {
                WindowsIdentity tempWindowsIdentity;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;
                if (RevertToSelf())
                {
                    if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                            LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                            if (impersonationContext != null)
                            {
                                CloseHandle(token);
                                CloseHandle(tokenDuplicate);
                                return true;
                            }
                        }
                    }
                }
                if (token != IntPtr.Zero)
                    CloseHandle(token);
                if (tokenDuplicate != IntPtr.Zero)
                    CloseHandle(tokenDuplicate);
                return false;
            }
            public void UndoImpersonation()
            {
                impersonationContext.Undo();
                impersonationContext.Dispose();
            }

            #endregion

     

     


            private void GetUserProfiles()
            {

                if (this.PartCacheRead(Storage.Shared, "<key>") != null)
                    _UserProfiles = this.PartCacheRead(Storage.Shared, "<key>") as Hashtable;
                else
                {
                    if (this.ImpersonateValidUser("<login>", "<domain>", "<password>"))
                    {

                        WSUserProfile.UserProfileService ups = new WSUserProfile.UserProfileService();
                        ups.Credentials = System.Net.CredentialCache.DefaultCredentials;

                        long profileCount = ups.GetUserProfileCount();
                        WSUserProfile.GetUserProfileByIndexResult up;
                        WSUserProfile.PropertyData[] propdata;


                        int index = 0;


                            for (int j = 0; j < profileCount; j++)
                            {
                                up = ups.GetUserProfileByIndex(index);
                                propdata = up.UserProfile;

                                index = int.Parse(up.NextValue);
          }

                        ups.Dispose();
                        this.UndoImpersonation();

                        this.PartCacheWrite(Storage.Shared, "<key>", _UserProfiles, TimeSpan.FromDays(7));
                    }

                          

                }

     

                       
        }

     

     

     

    jeudi 14 juin 2007 09:12
  • Bonjour,

    Même avec cette solution (qui est très lourde, et qui est plus pour SP2003), ça ne marche qu'avec un compte admin, et c'est toujours Forbidden pour un compte standard.

    C'est vraiment dommage qu'il n'y ait pas de fonctions permettant de lister (juste lister et consulter les donner) tous les utilisateurs...


    Je viens d'ouvrir une nouvelle discussion en essayant avec une autre méthode : lister les personnes d'une Groupe SharePoint. Facile me direz vous, mais comment faire quand il y a des listes de distribution de l'Active Directory ?


    http://forums.microsoft.com/MSDN-FR/ShowPost.aspx?PostID=1782801&SiteID=12


    ++

    mardi 26 juin 2007 09:38
  • Et une autre piste en passant les audiences, vous auriez p-e la possibilité de lister tous les membres sans lever cette exception ? (avec une audience regroupant tlm)
    mardi 26 juin 2007 13:18
  • Je viens d'essayer, malheureusement ça ne marche pas.
    mardi 26 juin 2007 14:24
  • salut,

     

    le code que j'ai posté fonctionne bien sous moss 2007.

    Même si la solution n'est pas des plus élégantes, ça a bien fonctionné sur le projet sur lequel j'ai bossé, notamment grâce à la mise en cache... mais c'est vrai qu'il n'y avait que 350 users environ.

     

    samedi 28 juillet 2007 20:33