Security Provider con ADAM en MOSS y WSS3

Es muy común disponer de autenticaciones sobre MOSS o WSS3 contra ADAM’s o distintas ramas de un dominio AD. En lugar de utilizar un desarrollo a medida utilizaremos la infraestructura de proveedores de Sharepoint.

Security Provider contra un ADAM

Active Directory Application Mode es una herramienta muy utilizada en proyectos en los que tenemos un repositorio de usuarios pero independiente del dominio.

Crearemos una instancia de ADAM

Podremos bajar el instalador de la página de Microsoft.

Creamos una instancia del ADAM, indicamos el nombre y el puerto de acceso.

ADAM1 ADAM2 ADAM3

Indicamos la raiz de nuestro ADAM.

ADAM4

El usuario del servicio sobre el que se ejecutará el ADAM y el usuario administrador

ADAM5 ADAM6

Indicamos la plantilla MS-user.LDF para poder crear usuarios.

ADAM7

Al finalizar, conectamos con la consola de ADAM y crearemos nuestra jerarquía y usuarios necesaria. Al crear el usuario, tendremos que desbloquearlos indicando el valor FALSE en el atributo msDS-UserAccountDisabled y estableceremos la password del usuario. En los atributos del usuario editaremos el campo «userPrincipalName» con el nombre de nuestro usuario. Este campo será el que utilicemos para realizar la búsqueda.

ADAM8 ADAM9

 

Por último indicaremos al ADAM que nuestro usuario tendrá permisos de administración para que nos podamos conectar desde fuera.

Iremos CN=Roles dentro en CN=Administrators y en la propiedad «member» añadiremos nuestro usuario del ADAM.

 

ADAM14 

 

Configuración del Web.Config

Una vez creado el ADAM tendremos que indicar a nuestra WebApplication que utilice el provider adecuado para autentificar los usuarios.

Para ello seleccionaremos la opción de «Proveedores de autenticación» de la consola de administración central, seleccionaremos la zona para la que queremos utilizar el provider y elegiremos autenticación por formulario y el nombre del provider. Al aceptar los cambios, nos modificará el Web.Config del WebApplication seleccionado.

ADAM10

A continuación daremos de alta el provider en el web.config del WebApplication seleccionado y en el WebApplication de la administración central. El motivo de darlo de alta en la administración central será para poder indicar el usuario administrador de nuestra colección. Si no hacemos esto, cuando intentemos acceder nos dará un error que no será capaz de encontrar el usuario administrador, ya que la colección tendrá asignado el usuario administrador del dominio y no el de nuestro provider.

ADAM11

Tener en cuenta que una vez activemos el provider para una zona todas las validaciones de esa zona las realizará con ese provider. Así si modificamos el provider para la zona predeterminada por defecto realizará la autenticación con ese provider y no con contra el dominio.

 

Autenticación de WSS3 con ADAM

Si navegáis por internet, vereis que todos los ejemplos de provider contra un ADAM son con MOSS. Esto es porque WSS3 no implementa un provider específico para LDAP. Pero si para una estructura similar a un AD.

Utilizaremos entonces «System.Web.Security.ActiveDirectoryMembershipProvider».

En nuestro caso hemos añadido dentro de system.web:

<membership >
      <providers>
             <add connectionStringName=»ADService» connectionUsername=»CN=admin,DC=MiRaiz,DC=COM«
               connectionPassword=»MiPassword» connectionProtection=»None«
              description=»Some description.» enableSearchMethods=»true»
              attributeMapUsername=»userPrincipalName«
              name=»MiADAMProvider» type=»System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a» />
      </providers>
    </membership>

Esta configuración la tendremos que indicar en el web.config del web application de la configuración central y de nuestra applicationweb que utilizará el provider. En este último caso si queremos que se utilice el provider para la zona por defecto tendremos que añadir :

<membership  defaultProvider=»MiADAMProvider»>
      <providers>
             <add connectionStringName=»ADService» connectionUsername=»CN=admin,DC=MiRaiz,DC=COM»
               connectionPassword=»MiPassword» connectionProtection=»None»
              description=»Some description.» enableSearchMethods=»true»
              attributeMapUsername=»userPrincipalName»
              name=»MiADAMProvider» type=»System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a» />
      </providers>
    </membership>

Una vez guardad la configuración no hará falta hacer un iisreset. Iremos a la página de administradores de colecciones escribiremos nuestro usuario y pulsaremos en el People Picker.

Si intentamos buscar el usuario desde la funcionalidad de «búsqueda de personas» del people picker, no nos devolverá nada, ya que tendremos que añadir lo siguiente:

http://blogs.msdn.com/dglover/articles/395594.aspx#395595

<PeoplePickerWildcards>
      <clear />
       <add key=»MiADAMProvider» value=»*» />
</PeoplePickerWildcards>

 

Una vez realizado los cambios ya podremos utilizar nuestro ActiveDirectoryMembershipProvideren Wss3!!!.

ADAM15

 

 

Fijaros que en las credenciales de conexión con el LDAP hemos utilizado un usuario del propio ADAM. Yo no he conseguido conectar con usuario del AD, he tenido muchísimos problemas, al final creo que es un problema de envío de contraseñas al conectar con el ADAM.

 

Autenticación de MOSS con ADAM

Sobre MOSS utilizaremos «Microsoft.Office.Server.Security.LDAPMembershipProvider«.

En nuestro ejemplo:

<membership defaultProvider=»MiADAMProvider»>
      <providers>
          <add name=»MiADAMProvider» type=»Microsoft.Office.Server.Security.LDAPMembershipProvider, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C»
               server=»testpcserver» port=»50010″ useSSL=»false» userDNAttribute=»displayName» userNameAttribute=»CN»
               userContainer=»DC=MiRaiz,DC=com» userFilter=»|(ObjectClass=user)(ObjectClass=organizationalUnit)»
               userObjectClass=»user» scope=»Subtree» otherRequiredUserAttributes=»sn,givenname,cn» />
      </providers>
    </membership>

 

 

Enlaces que me ayudaron

http://msdn2.microsoft.com/en-us/library/ms998360.aspx

http://blogs.msdn.com/dansellers/archive/2005/10/11/479941.aspx

http://msdn.microsoft.com/en-us/library/aa479048.aspx

http://msdn.microsoft.com/en-us/library/system.web.security.activedirectorymembershipprovider.aspx

http://msdn.microsoft.com/en-us/library/system.web.security.activedirectorymembershipprovider.aspx

http://msdn.microsoft.com/en-us/library/aa479048.aspx

http://www.tutorials-win.com/ActiveDirectory/ADAMs-replica/

Asignación CAS de Sharepoint por contexto de usuario

Puesta en situación


En uno de nuestros proyectos hemos tenido que manejar el contexto del usuario en el negocio con el contexto de sharepoint. Consiste en que el cliente dispone de un conjunto de usuarios que están en la central, y otro dispersos por el territorio nacional, asociados en centros o delegaciones.  Una de las funcionalidades que disponía era la de enviar solicitudes desde los centros a la central. Lo que queríamos era que desde una misma página cada usuario solo viera las solicitudes creadas por los usuarios de su centro, y los gestores los de todos los centros.


La solución que pensamos fué la siguiente:


Cada solicitud tendría un CustomField con el centro que crea la solicitud. Este campo se encargaría de determinar el centro al que está asignado el usuario y asignar a la solicitud los permisos de seguridad correspondientes para que lo vieran solo los gestores y los usuarios del centro que lo creo. Para gestionar la seguridad creamos un grupo de seguridad para cada centro, y asignamos los usuarios al centro que le correspondía. Para relacionar Grupo de seguridad con Centro, utilizamos una lista personalizada con los centros disponibles.


Al crear una nueva solicitud, el CustomField detectaba el centro al que pertenecía el usuario comparando la lista de centros con los grupos de seguridad, y a continuación modificaba los permisos CAS del nuevo elemento.


 


Feature


Creamos una Feature de Wss3 para encapsular los componentes y asignar el EventReceiver a las listas al activarse la Feature.


 


CustomField de Wss3


Utilizamos un customField de tipo texto para almacenar el centro que crea la solicitud. Para que el usuario no tuviera que seleccionar su centro, quitamos el campo de los formularios de edición.


 


public class CentroCustomField : SPFieldText
    {
        ……………..


        /// <summary>
        /// Devuelve toda la lista de centros
        /// </summary>
        /// <returns></returns>
        private List<string> LoadAllCentros(){
            List<string> allCentros = new List<string>();
            try{
                SPList centrosList = SPContext.Current.Web.GetList(string.Format(«{0}/Lists/Centros», SPContext.Current.Web.Name));
                if(centrosList != null){
                    foreach(SPItem centro in centrosList.Items){
                        allCentros.Add((string)centro[«NombreCentro»]);
                    }
                }
            }catch(Exception ex){
            }
            return allCentros;
        }
      }


      ……………..


        protected override void CreateChildControls() {
            try{
              if (this.Field == null || this.ControlMode == SPControlMode.Display)
                return;
              base.CreateChildControls();


              this.CentroSelector = (DropDownList)TemplateContainer.FindControl(«CentroSelector»);

              if (this.CentroSelector == null)
                throw new Exception(«Control CentroFieldControl.ascx corrupto.»);

              if (!this.Page.IsPostBack)
              {
                  if (m_allCentros != null)
                  {
                      this.CentroSelector.Items.Add(» «);
                      this.CentroSelector.Items.Add(«Todos»);
                      foreach (string nombreCentro in m_allCentros)
                      {
                          this.CentroSelector.Items.Add(nombreCentro);
                      }
                  }
              }
            }catch(Exception ex){
            }
          }



……………..


    }


Event Handler


Para que nuestro campo supiera que centro debe asignar a la solicitud creamos un event receiver al agregar un elemento a nuestra lista de solicitudes.


Para registrar el event receiver utilizamos la activación de la feature:


 


public class FeatureReceiver : SPFeatureReceiver
   {

       public override void FeatureActivated(SPFeatureReceiverProperties properties)
       {
           try
           {
               SPWeb site = SPContext.Current.Web;

               string asmName = «FeatureCentros, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ea8da11d5c8d53be»;
               string itemReceiverName = «XXXXXXX.CentroEventReceiver»;

               SPList listaSolicitudes = site.Lists[«Solicitudes»];
               listaSolicitudes.EventReceivers.Add(SPEventReceiverType.ItemAdded,
                                             asmName,
                                             itemReceiverName);

               listaSolicitudes.Update();

           }
           catch { }
       }

}


Para que la feature sepa que debe ejecutar el Event Receiver indicamos en la feature


<Feature Id=»FE642B14-97FF-4a72-85F2-984FBD0A7D14″
   Title=»Herramientas de Centros»
   Description=»XXXXXXXXXXXXX»
   Version=»1.0.0.0″
   Scope=»Web»
   Hidden=»FALSE»
   ImageUrl=»XXXXXXX.jpg»
   ReceiverAssembly=»FeatureCentros, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ea8da11d5c8d53be»
   ReceiverClass=»XXXXXX.FeatureReceiver»
   xmlns=»http://schemas.microsoft.com/sharepoint/»>

  <ElementManifests>


………………………..
  </ElementManifests>


</Feature>

 


Event Receiver


Creamos un EventReceiver para que cuando se añada un elemento a la lista se apliquen los permisos correspondientes.


 


public class CentroEventReceiver : SPItemEventReceiver
    {

        public override void ItemAdded(SPItemEventProperties properties)
        {
            try
            {
                        if ((string)properties.ListItem[«Centro»] != «Todos»)
                        {
                            // Buscamos el centro asociado al usuario
                            SPUser usuario = properties.ListItem.ParentList.ParentWeb.CurrentUser;

                            using (SPWeb webOrigUser = properties.OpenWeb())
                            {
                                SPUserToken token = webOrigUser.AllUsers[«SHAREPOINT\system»].UserToken;
                                using (SPSite site = new SPSite(properties.SiteId, token))
                                {
                                    using (SPWeb currentWeb = site.OpenWeb(properties.RelativeWebUrl))
                                    {

                                        Dictionary<string, SPGroup> gruposAsociados = new Dictionary<string, SPGroup>();
                                        foreach (SPGroup grupo in usuario.Groups)
                                        {
                                            gruposAsociados.Add(grupo.Name, grupo);
                                        }

                                        List<SPGroup> centrosAsociados = new List<SPGroup>();
                                        SPList centrosList = currentWeb.GetList(string.Format(«{0}/Lists/Centros», currentWeb.Name));
                                        if (centrosList != null)
                                        {
                                            foreach (SPItem centro in centrosList.Items)
                                            {
                                                string nombreCentroLeido = (string)centro[«NombreCentro»];
                                                if (gruposAsociados.ContainsKey(nombreCentroLeido))
                                                {
                                                    centrosAsociados.Add(gruposAsociados[nombreCentroLeido]);
                                                }
                                            }
                                        }

                                        if (centrosAsociados.Count > 0)
                                        {
                                            try
                                            {
                                               DisableEventFiring();

                                                // Asignamos el primer centro al campo en caso de no ir relleno
                                                if ((string)properties.ListItem[«Centro»] == » «)
                                                {
                                                    properties.ListItem[«Centro»] = centrosAsociados[0].Name;
                                                }

                                                //// Asignamos los CAL que correspondan
                                                SPList listaAModificar = currentWeb.Lists[properties.ListId];
                                                SPListItem itemAModificar = listaAModificar.GetItemById(properties.ListItem.ID);
                                                if (!itemAModificar.HasUniqueRoleAssignments)
                                                    itemAModificar.BreakRoleInheritance(true);



                                                List<SPRoleAssignment> RoleABorrar = new List<SPRoleAssignment>();
                                                SPRoleAssignmentCollection roleAssignmentCollection = itemAModificar.RoleAssignments;
                                                foreach (SPRoleAssignment roleAssignment in roleAssignmentCollection)
                                                {
                                                    if (roleAssignment.Member.Name != «Gestores»                    &&
                                                        roleAssignment.Member.Name != «Consultores»                 &&
                                                        roleAssignment.Member.Name != «Propietarios eLogosPiloto»   &&
                                                        roleAssignment.Member.Name != «Cuenta del sistema»          &&
                                                        roleAssignment.Member.Name != centrosAsociados[0].Name      &&
                                                        roleAssignment.Member.Name != (string)properties.ListItem[«Centro»])
                                                    {
                                                        RoleABorrar.Add(roleAssignment);
                                                    }
                                                }
                                                foreach (SPRoleAssignment roleAssignment in RoleABorrar)
                                                    roleAssignmentCollection.Remove(roleAssignment.Member);


                                                itemAModificar.Update();

                                            }
                                            catch (Exception ex)
                                            {

                                            }
                                            finally
                                            {
                                                EnableEventFiring();
                                            }
                                        }
                                    }
                                }
                            }
                        }
               
            }
            catch (Exception ex)
            {
            }
        }

    }

Fijaros en algunos detalles:


SPUserToken token = webOrigUser.AllUsers[«SHAREPOINT\system»].UserToken;
using (SPSite site = new SPSite(properties.SiteId, token))
{
    using (SPWeb currentWeb = site.OpenWeb(properties.RelativeWebUrl))
    {


Este trozo de código hace que el código se ejecute con los permisos asociados al usuario «SHAREPOINTsystem» para que podamos realizar determinadas tareas de administración. Si no ejecutáramos nuestro código con privilegios al hacer un BreakRoleInheritance nos lanzaría una excepción del tipo  UnauthorizedAccessException.


El objetivo es que se ejecutara con permisos de administración, para ello podríamos haber utilizado un código similar al siguiente:


SPSecurity.RunWithElevatedPrivileges(delegate()

{

  SPUserToken token = webOrigUser.AllUsers[WindowsIdentity.GetCurrent().Name].UserToken;
  using (SPSite site = new SPSite(properties.SiteId, token))
  {
    using (SPWeb currentWeb = site.OpenWeb(properties.RelativeWebUrl))
     {


Esto funcionará siempre que tengamos activado en el fichero Web.config: <Identity Impersonate=”true”>


Fijaros en el código que estamos obteniendo una nueva referencia de SPSite, SPWeb y SPItem en lugar de utilizar las propiedades del parámetros del EventReceiver «SPItemEventProperties properties». Esto es debido a que necesitamos obtener las referencias al elemento que queremos modificar con las credenciales del usuario administrador.


 


DisableEventFiring: Permite que cualquier cambio que hagamos no provoque la ejecución de un workflow.

GetItemById: Hemos utilizado esta función en lugar de la colección Items, porque Items solo contiene los elementos disponibles antes de ejecutarse el evento y GetItemById es capaz de localizar el nuevo elemento.

BreakRoleInheritance: Rompe la herencia del contendor (la lista), para poder editar nuestros propios permisos. El valor True indica que copie todos los grupos que hereda de la lista, un valor False ´lo dejaría sin grupos. Un detalle, cada vez que utilicemos esta función tendremos que hacer un Dispose del Parent del elemento, tal y como se comenta en el blog de Roger Lamb’s

RoleAssignments: Es la colección de grupos de sharepoint asignados automáticamente al elemento.

Opciones del QuickLaunch de Wss3 mediante SPNavitaionProvider

Un problema muy común en WSS3 es el de conseguir un menú de navegación que muestre las opciones en función del usuario y las unidades de negocio que estén activas en el portal.

El menú de navegación de wss3 nos permite navegar a las distintas listas o bibliotecas que creemos. También nos permite dar de alta nuestras propias opciones desde la página de configuración de inicio rápido.

El problema que tendremos en un proyecto real, será que las opciones que tengan que aparecer dependerán del usuario logado y los elementos de negocio implementados, y no podrán ser opciones estáticas.

 

Ejemplo del problema en el mundo real

En Renacimiento estamos trabajando en un cliente que tiene que desplegar más de 150 portales con una infraestructura Wss3 (no MOSS), cada portal puede tener activo una serie de features que en conjunto implementan las funcionalidades requeridas por el negocio. Al activarse cada elemento muestra en el menú principal una serie de opciones propias del elemento o unidad de negocio. Además, en función del rol del usuario puede visualizar o no esas opciones. Esto implica que el mantenimiento de las opciones por el menú de inicio rápido sea bastante limitado para el proyecto.

Para ello, hemos utilizado nuestro propio SPNavigationProvider que consume una lista personalizada de Wss3 como repositorio de las opciones del QuickLaunch Menu.

 

SPNavigationProvider

Es un proveedor de navegación que se ocupa de proporcionar las opciones que visualizará un menú de navegación. Este clase no se encarga de visualizar las opciones, sino de obtenerlas de un repositorio.

SPNavigationProvider es una clase que hereda de SiteMapProvider estándar en Asp.Net2.

System.Object
System.Configuration.Provider.ProviderBase
System.Web.SiteMapProvider
Microsoft.SharePoint.Navigation.SPNavigationProvider

 

How To

Para conseguir que nuestro QuickLaunch Menu obtenga las opciones de una lista personalizada tendremos que crear una clase que herede de SPNavitaionProvider e implementar el método GetChildNodes, después configurar el nuevo proveedor y modificar nuestra masterpage para que utilice el proveedor.

 

Custom SPNavitaionProvider

Crearemos una clase que herede de SPNavitaionProvider. Para hacerlo crearemos un proyecto Dll de windows.

Agregaremos al proyecto las referencias:

System.Configuration

System.Web

Microsoft.Sharepoint

 

Importaremos las referencias en nuestra clase:
using System.Collections.Generic;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;

 

A continuación definimos nuestra clase, hacemos que herede de SPNavitaionProvider, y sobre-escribimos el método GetChildNodes.

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;

namespace MyMenuProvider
{
    public class MyMenuProvider : SPNavigationProvider
    {
        public override System.Web.SiteMapNodeCollection GetChildNodes(System.Web.SiteMapNode node)
        {
           ……

        }
    }
}

 

En nuestros caso de ejemplo hemos creado una lista de wss3 con un nivel de profundidad:

Lista

Opciones

 

namespace MyMenuProvider
{
    public class MyMenuProvider : SPNavigationProvider
    {
       

        public override System.Web.SiteMapNodeCollection GetChildNodes(System.Web.SiteMapNode node)
        {
            System.Web.SiteMapNodeCollection opciones = new System.Web.SiteMapNodeCollection();;
            try
            {
                if (node.Title == «Inicio rápido»)
                {
                    System.Web.SiteMapNode rootOpcion = new System.Web.SiteMapNode(this, «Mis Opciones», «/», «Mis Opciones», «»);
                    opciones.Add(rootOpcion);
                }
                if (node.Title == «Mis Opciones»)
                {
                    SPWeb site = SPContext.Current.Web;
                    SPList listaOpciones = site.Lists[«Opciones»];

                    SPQuery query = new SPQuery();
                    query.ViewFields = «<FieldRef Name=’Title’ /><FieldRef Name=’Url’ /><FieldRef Name=’Orden Opcion’ />»;

                    SPListItemCollection opcionesLeidas = listaOpciones.GetItems(query);
                    foreach (SPListItem opcionLeida in opcionesLeidas)
                    {
                        System.Web.SiteMapNode nuevaOpcion = new System.Web.SiteMapNode(this, (string)opcionLeida[«Title»], (string)opcionLeida[«Url»], (string)opcionLeida[«Title»], (string)opcionLeida[«Title»]);
                        opciones.Add(nuevaOpcion);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Web.SiteMapNode exOpcion = new System.Web.SiteMapNode(this, «Excepción», «», ex.Message, ex.Message);
                opciones.Add(exOpcion);
            }
            return opciones;
        }

    }
}

 

A continuación firmamos la dll con un strong name y construimos nuestra dll.

 

Configurar el Web Config

Tendremos que indicar en el Web.Config de nuestra Web Application la configuración del nuevo provider de navegación. Abriremos el web.config y lo editaremos.

Para que esté disponible el proveedor es imprescindible que la aplicación de wss3 sepa encontrar la dll, para ello podremos registrar la dll en el GAC (Lo más recomendable), o copiarlo en el directorio «bin» de la aplicación web. Si haceis modificaciones en la dll una vez registrada en el web.config tendreis que hacer un iisreset para que obtenga los cambios.

 

Abriremos entonces el WebConfig y editaremos la sección «siteMap»:

<siteMap defaultProvider=»SPSiteMapProvider» enabled=»true»>
      <providers>
        <add name=»SPNavigationProvider» type=»Microsoft.SharePoint.Navigation.SPNavigationProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c» />
        <add name=»SPSiteMapProvider» type=»Microsoft.SharePoint.Navigation.SPSiteMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c» />
        <add name=»SPContentMapProvider» type=»Microsoft.SharePoint.Navigation.SPContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c» />
        <add name=»SPXmlContentMapProvider» siteMapFile=»_app_bin/layouts.sitemap» type=»Microsoft.SharePoint.Navigation.SPXmlContentMapProvider, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c» />
        <add name=»MyMenuProvider» type=»MyMenuProvider.MyMenuProvider, MenuProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=160b265bda309c7a» />
      </providers>
    </siteMap>

 

Un error muy común es confundirse en el Namespace y en nombre del assembly, revisarlo bien antes de continuar.

 

Configurar el QuickLaunch Menu

Ya tendremos entonces disponible nuestro provider de navegación, ahora solo tendremos que indicar en nuestra masterpage al SPNavigationManager el nuevo Provider de navegación.

En nuestro ejemplo hemos creado una nueva masterpage y hemos hecho las modificaciones sobre ella.

Buscamos la sección «Sharepoint:SPNavigationManager» y modificamos la propiedad «SiteMapProvider» del siteMapDatasource por el nombre de nuestro provider.

<Sharepoint:SPNavigationManager
                id=»QuickLaunchNavigationManager»
                runat=»server»
                QuickLaunchControlId=»QuickLaunchMenu»
                ContainedControl=»QuickLaunch»
                EnableViewState=»false»>
                <div>
                    <SharePoint:DelegateControl runat=»server»
                        ControlId=»QuickLaunchDataSource»>
                     <Template_Controls>
                        <asp:SiteMapDataSource
                        SiteMapProvider=»MyMenuProvider»
                        ShowStartingNode=»False»
                        id=»QuickLaunchSiteMap»
                        StartingNodeUrl=»sid:1025″
                        runat=»server»
                        />
                    …………………………………
                </div>
                </Sharepoint:SPNavigationManager>

Una vez configurado en el masterpage, las páginas que la utilicen tendrán opciones de menú distintas a las del menú de inicio rápido.

Ahora solo tendremos que añadir en nuestra lista las opciones que necesitemos y configurar los permisos de cada una para cada grupo de usuarios.Con esto habremos conseguido que sea Wss3 quien gestione que opciones puede ver cada usuario.

 opcionesmenu

 

Es importante que reviséis el  código del provider, ya que se va a ejecutar varias veces por cada petición de una misma página. Por cada nodo que añadamos ejecutará el método Getchild, por lo que habrá que controlar la recursividad con el parámetro de la función y el método FindSiteMapNode.

 

Otras opciones

Existen más opciones para conseguir que nuestro menú de navegación muestre las opciones en función de las reglas de negocio y seguridad.

Algunos utilizan listas como repositorio de opciones, pero para visualizarlo utilizan un DataFormWebPart y modifican el xsl para dejarlo con el diseño del portal.

Otros prefieren utilizar listas como repositorio, pero en lugar del menú estándar crean su propio control de usuario y lo añaden a la masterpage.

También existe la copión de hacerse un menú de ASp.NEt a medida.

 

Existen muchas opciones, cada uno que elija la que mejor le venga. Pero como conclusión, el trabajar con proveedores como comentaba Jorge Diéguez nos aporta bastante grado de modularidad.