Accès refusé lors de l’édition d’un item dans une liste SharePoint 2007

Lorsque vous modifiez les propriétés d’un item pour lequel vous avez toutes les permissions, vous obtenez malgré tout une erreur "accès refusé".

Ce problème connu est décrit dans l’article https://support.microsoft.com/kb/961175. Cependant, le correctif n’agit que pour les nouvelles collections de sites, celles déjà affectées doivent être corrigées différemment.

Le problème est dû à la colonne "Effective Permission Mask" (son nom interne est "PermMask") qui doit avoir l’attribut "RenderXMLUsingPattern" à "true".

Pour que la modification fonctionne dans tous les scénarios (listes existantes, création de nouvelles listes dans le site courant et dans un sous site), la colonne doit être modifiée au niveau du site web racine, et sur chaque liste du site et de ses sous sites.

Le modèle objet de SharePoint nous permet de mettre à jour facilement une colonne, et de propager la modification sur les colonnes enfant. Malheureusement, l’attribut RenderXMLUsingPattern ne peut se mettre à jour qu’à travers la propriété SchemaXml, et comme indiqué dans cette page du msdn, on ne peut pas utiliser la méthode SPField.Update pour mettre à jour la colonne avec toutes ses colonnes filles.

Il faut donc récursivement parcourir les sous-sites pour mettre à jour chaque liste une à une. Ce blog fournit un exemple pour mettre à jour un site ou une liste de façon unitaire, mais le code ci-dessous permet de mettre à jour l’intégralité d’une collection de sites :

Attention, ce code n’est qu’un exemple fourni tel quel sans aucune garantie d’aucune sorte et vous l’utilisez à vos risques et périls. Il vous appartient de revoir, compiler, tester et valider ce code. L’auteur ou Microsoft ne peut en aucun cas être tenu pour responsable de tout dommage de quelque nature que ce soit, direct ou indirect suite à l’utilisation de celui-ci.

 static string AttributeToUpdate = "RenderXMLUsingPattern";
static string AttributeValue = "TRUE";
static string FieldInternalNameToUpdate = "PermMask";

static public void UpdateField(SPField field)
{
    XmlDocument xd = new XmlDocument();
    xd.LoadXml(field.SchemaXml);
    XmlElement xe = xd.DocumentElement;

    // If attribute does not exist, create it
    if (xe.Attributes[AttributeToUpdate] == null)
    {
        Console.WriteLine("Creating attribute {0}...", AttributeToUpdate);
        XmlAttribute attr = xd.CreateAttribute(AttributeToUpdate);
        attr.Value = AttributeValue;
        xe.Attributes.Append(attr);
    }

    // If attribute exist but not correctly set, update it
    if (String.Equals(xe.Attributes[AttributeToUpdate].Value, "false", StringComparison.InvariantCultureIgnoreCase))
    {
        Console.WriteLine("Updating attribute {0}...", AttributeToUpdate);
        xe.Attributes[AttributeToUpdate].Value = AttributeValue;
    }

    // Perform the update
    field.SchemaXml = xe.OuterXml;
}

static public void UpdateSiteField(string siteCollectionUrl, bool updateSubwebs)
{
    using (SPSite osite = new SPSite(siteCollectionUrl))
    {
        SPWeb rootWeb = osite.RootWeb;
        try
        {
            Console.WriteLine("Check web {0} ({1})", rootWeb.Title, rootWeb.Url);
            UpdateField(rootWeb.Fields.GetFieldByInternalName(FieldInternalNameToUpdate));

            for (int i = 0; i < rootWeb.Lists.Count; ++i)
            {
                UpdateField(rootWeb.Lists[i].Fields.GetFieldByInternalName(FieldInternalNameToUpdate));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("An exception occured during the execution: {0} in ({1})", ex.Message, ex.StackTrace);
        }

        if (updateSubwebs)
            RecursiveWeb(rootWeb);
    }
}

static private void RecursiveWeb(SPWeb parentWeb)
{
    foreach (SPWeb InnerWeb in parentWeb.Webs)
    {
        try
        {
            Console.WriteLine("Check web {0} ({1})", InnerWeb.Title, InnerWeb.Url);
            for (int i = 0; i < InnerWeb.Lists.Count; ++i)
            {
                UpdateField(InnerWeb.Lists[i].Fields.GetFieldByInternalName(FieldInternalNameToUpdate));
            }
            RecursiveWeb(InnerWeb);
        }
        finally
        {
            if (InnerWeb != null)
                InnerWeb.Dispose();
        }
    }
}

De Yvan Duhamel, Ingénieur support d’escalade sur SharePoint