This Blog

Syndication

Search

Tags

Community

Email Notifications

Archives

Enlaces Recomendados

MOSS: Leyendo los user profiles

Uno de los retos que se nos ha planteado en el CIIN es como visualizar el directorio de empleados de una organización (que en este caso se encuentra en una estructura de directorio activo, DA) en un team site de MOSS utilizando las capacidades que este nos aporta.  El primer punto a tener en cuenta es que MOSS a través de los Shared Services Providers (SSP), y en concreto el SSP referente a User Profiles, nos permite cargar la información de todos los usuarios de una organización de manera manual o automática definiendo un origen de importación que puede ser un DA, un recurso de DA, un directorio LDAP o bien un Business Data Catalog (BDC).

(Como ocurría con la configuración de la búsqueda, la importación automática de perfiles se puede programar con una cierta periodicidad. Mi compañero Pablo me ha prometido que contará en detalle cómo se realiza la importación de profiles de un DA en su próximo post, ya veréis que es algo realmente interesante y con algún truquito que otro.).

Una vez importados los perfiles de usuario, el listado de los mismos es visible desde la administración central de MOSS (en el SSP Perfiles de usuarios y propiedades-> Ver perfiles de usuario).

Cada user profile tiene un serie de propiedades, muchas de las cuáles coinciden con las que presenta un DA para los distintos usuarios que almacena. Pero, ¿Cómo podemos ver este listado de usuarios fuera de la administración central? ¿Se podría además ver para cada usuario la ficha de detalle del mismo?  La pregunta difícil es la primera, puesto que una vez sepamos como listar los user profiles fuera de la administración central, visualizar el detalle de un profile en concreto no tiene porque ser complejo.

Alternativas para visualizar los user profiles fuera de la administración central

Para visualizar todos los user profiles creados, hay varias alternativas:

·         A través de crear un sitio de búsqueda específico pare personas, de manera que una vez realizada la correspondiente indexación podremos buscar usuarios concretos en el listado importado.

·         Atacando el servicio web UserProfile.asmx de nuestra máquina MOSS y mostrando el listado de usuarios en una web part o en una lista de MOSS.

·         Atacando el modelo de objetos de MOSS y mostrando el listado de usuarios en una web part o en una lista.

En nuestro caso, hemos optado por la tercera opción y como no queremos duplicar la información de los profiles en una lista, construiremos una web part que permita mostrar el listado de profiles y que al seleccionar un profile concreto permita ver el detalle del mismo de forma similar al estilo preview panel de una lista de WSS 3.0 / MOSS:

Resolviendo el problema

Tras una serie de pruebas de concepto sobre como leer los user profiles y ver que objetos hay que manejar para cumplir con los requerimientos comentados, pasamos a crear la web part correspondiente. Para agilizar el proceso de creación, y despliegue posterior de la web part utilizamos las extensiones de WSS 3.0 para Visual Studio (aprovecho para comentar que es una pena que no estén oficialmente soportadas por Microsoft). Ya comentamos en un post previo, que al utilizar estas extensiones se añaden las extensiones e infrasestructura necesaria para desplegar la web part sin más que hacer el deploy de la solución.

Para poder trabajar con los user profiles, y construir una web part que dinámicamente muestra un listado de los mismos y permite visualizar el detalle del profile seleccionado necesitamos añadir e importa al proyecto los siguientes espacios de nombres:

using System.Web.UI.WebControls;

using System.Data;

using Microsoft.Office.Server;

using Microsoft.Office.Server.UserProfiles;

using System.Web;

using System.Drawing;

En negrita he marcado los espacios de nombres necesarios para atacar los user profiles. El resto de espacios de nombres se utilizan para la visualización de los profiles. Antes de seguir, os voy a mostrar (esto es lo que se dice empezar por el final) que pinta tiene la web part que finalmente se despliega para enlazarlo con los pasos de creación:

Los pasos para llegar a construir la web part anterior son los siguientes:

Sobreescribir el método CreateChildControls()

Lo primero que haremos en el código de la web part es sobreescribir el método CreateChildControls(), que nos permitirá crear todos los controles que va a incluir nuestra web part (y que se construyen de manera dinámica en base a la información de los user profiles). Antes de crear los controles hijos necesarios, es en este método donde obtendremos el listado de profiles que tenemos importados / creados en el SSP de MOSS. Para el caso expuesto, el código necesario para la recuperación de los user profiles es el siguiente:

                SPSite spsSitio = SPControl.GetContextSite(this.Context);

                ServerContext scContexto = ServerContext.GetContext(spsSitio);

                UserProfileManager upManager = new UserProfileManager(scContexto);

 

                //Construimos la tabla con las columnas que nos interesan

                dtData.Columns.Add(ID_PROFILE);

                dtData.Columns.Add(CAMPO1_PROFILE);

                dtData.Columns.Add(CAMPO2_PROFILE);

                dtData.Columns.Add(CAMPO3_PROFILE);

                dtData.Columns.Add(CAMPO4_PROFILE);

                dtData.Columns.Add(CAMPO5_PROFILE);

                dtData.Columns.Add(CAMPO6_PROFILE);

                dtData.Columns.Add(CAMPO7_PROFILE);

                dtData.Columns.Add(CAMPO8_PROFILE);

                dtData.Columns.Add(CAMPO9_PROFILE);

 

                //Llenamos la tabla

                foreach (UserProfile cUser in upManager)

                {

                    UserProfileValueCollection upValue;

                    dtRow = dtData.NewRow();

                    foreach (Property pPropiedad in cUser.ProfileManager.Properties)

                    {

                        //ID

                        if (pPropiedad.Name == ID_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo1

                        if (pPropiedad.Name == CAMPO1_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo2

                        if (pPropiedad.Name == CAMPO2_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo3

                        if (pPropiedad.Name == CAMPO3_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo4

                        if (pPropiedad.Name == CAMPO4_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo5

                        if (pPropiedad.Name == CAMPO5_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo6

                        if (pPropiedad.Name == CAMPO6_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo7

                        if (pPropiedad.Name == CAMPO7_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //campo8

                        if (pPropiedad.Name == CAMPO8_PROFILE)

                        {

                            upValue = cUser[pPropiedad.Name];

                            dtRow[upValue.Property.Name] = upValue.Value;

                        }

                        //Campo9

                        if (dtRow[CAMPO3_PROFILE].ToString() != "" || dtRow[CAMPO4_PROFILE].ToString() != "")

                        {

                            if (dtRow[CAMPO4_PROFILE].ToString() == "")

                            {

                                dtRow[CAMPO9_PROFILE] = dtRow[CAMPO3_PROFILE];

                            }

                            else

                            {

                                dtRow[CAMPO9_PROFILE] = dtRow[CAMPO3_PROFILE] + "- " + dtRow[CAMPO4_PROFILE];

                            }

 

                        }

 

                    }

                    dtData.Rows.Add(dtRow);

                }

Como vemos, una vez obtenido el sitio (a través de spsSitio que es un objeto de tipo SPSite y utilizando el método GetContext para obtener el sitio actual) en el que se va a ejecutar la web part y el contexto del servidor (objeto scContexto, de tipo ServerContext y utilizando el método GetContext para obtener el contexto actual), los perfiles de usuario almacenados en nuestro servidor de MOSS se obtienen a partir de un objeto de tipo UserProfileManager (clase utilizada para acceder a los datos de perfiles de usuario) que a partir del contexto del servidor nos devuelve una colección de objetos de tipo UserProfile. Una vez que tenemos la colección de user profiles, lo siguiente que hacemos es recorrerla y nos quedamos con las propiedades que nos interesan de cada user profile. Para ello:

·         En el primer nivel de anidamiento, vamos recorriendo cada objeto de tipo UserProfile almacenado en la colección de user profiles.

  foreach (UserProfile cUser in upManager)

 

·         En el segundo nivel de anidamiento, seleccionamos las propiedades que nos interesen de cada user profile.

                foreach (UserProfile cUser in upManager)

                {

                    UserProfileValueCollection upValue;

                    dtRow = dtData.NewRow();

                    foreach (Property pPropiedad in cUser.ProfileManager.Properties)

                    {

En este segundo nivel, para realizar el recorrido por la colección de propiedades (cUser.ProfileManager.Properties) de cada user profile estamos utilizando un objeto de UserProfiles.Property, que es la clase que representa la definición para una propiedad de un user profile. Finalmente, cada propiedad que necesitemos la estamos almacenando en el objeto upValue que es de tipo UserProfileValueCollection, que nos permite construir una colección con las propiedades que nos interese visualizar para cada user profile. A continuación, cada propiedad la asignamos a un objeto de tipo DataRow que luego añadiremos al objeto DataTable que aparece al principio del listado. Este último objeto es el que finalmente utilizaremos para construir la web part, tanto para visualizar la lista de user profiles como para luego mostrar el detalle del user profile seleccionado.

Una vez que tenemos los user proflies, ya podemos empezar a construir los controles hijos que constituirán nuestra web part.

                ////Tabla Principal

                tblContenedor = new Table();

 

                //Añadimos una fila       

                tblRow = new TableRow();

 

                //Lista Empleados       

                tblCell = new TableCell();

                tblListaEmpleados = new Table();

                tblCell.Controls.Add(this.tblListaEmpleados);

                tblRow.Cells.Add(tblCell);

 

                //Detalle Empleado       

                tblCell = new TableCell();

                this.tblDetalleEmpleado = new Table();

                this.tblDetalleEmpleado.CssClass = ESTILOS_FICHA_EMPLEADO;

                tblCell.Controls.Add(this.tblDetalleEmpleado);

                tblRow.Cells.Add(tblCell);

 

                //Lo añadimos todo a la tabla principal...

                this.tblContenedor.Rows.Add(tblRow);

 

                //Radiobutton

                rdbListaEmpleados = new RadioButtonList();

                rdbListaEmpleados.EnableViewState = true;

                rdbListaEmpleados.AutoPostBack = true;

                this.rdbListaEmpleados.SelectedIndex = 0;

                this.rdbListaEmpleados.CssClass = ESTILOS_LISTA_EMPLEADOS;

 

                this.rdbListaEmpleados.DataSource = dtData;

                this.rdbListaEmpleados.DataValueField = ID_PROFILE;

                this.rdbListaEmpleados.DataTextField = CAMPO9_PROFILE;

                this.rdbListaEmpleados.DataBind();

                //Evento para el radiobutton

                this.rdbListaEmpleados.SelectedIndexChanged +=

                    new System.EventHandler(this.rdbListaEmpleados_SelectedIndexChanged);

 

                //Añadimos el radiobutton list a la tabla

                tblRow = new TableRow();

                tblCell = new TableCell();

                tblCell.Controls.Add(this.rdbListaEmpleados);

                tblRow.Cells.Add(tblCell);

                tblContenedor.EnableViewState = true;

                //Añadiendo las celdas a la tabla

                this.tblListaEmpleados.Rows.Add(tblRow);

 

                if (dtData.Rows.Count > 0)

                {

                    this.Controls.Add(this.tblContenedor);

 

                }

Lo más interesante del código anterior (la presentación de la información utilizando una tabla principal que contiene otras dos tablas que contendrán el listado de usuarios por un lado, y el detalle del empleado seleccionado es lo de menos) es lo siguiente:

·         La fuente de datos utilizada para rdbListaEmpleados es justo el objeto DataTable construido a partir de los datos de los perfiles de usuario. En concreto, estamos utilizando los campos ID_PROFILE que contiene el ID único para cada user profile (propiedad UserProfile_GUID de cada user profile) y CAMPO9_PROFILE (que contiene la concatenación de los campos PreferredName y WorkPhone), el primero lo vinculamos a la propiedad DataValueField de rdbListaEmpleados y el segundo a la propiedad DataTextField.

                this.rdbListaEmpleados.DataSource = dtData;

                this.rdbListaEmpleados.DataValueField = ID_PROFILE;

                this.rdbListaEmpleados.DataTextField = CAMPO9_PROFILE;

                this.rdbListaEmpleados.DataBind();

 

·         La forma en que se añade el manejador para el evento SelectedIndexChanged del control rdbListaEmpleados que es de tipo RadioButtonList():

                this.rdbListaEmpleados.SelectedIndexChanged +=

                    new System.EventHandler(this.rdbListaEmpleados_SelectedIndexChanged);

Como vemos, el manejador se añade a rdbListaEmpleados utilizando la forma ya conocida de añadir manejadores en C# para controles web o de Windows forms. Algo importante es que tenemos que configurar la propiedad AutoPostBack a True para que se pueda disparar el evento SelectedIndexChanged de rdbListaEmpleados y se ejecute el manejador.

·         Como se añaden los controles hijos a la web part, y que como ya habéis visto y conoceréis, implica hacer una llamada del método Add() de la colección de controles de la web part (en este caso, lo mismo se utiliza cuando creamos user controls, páginas ASP.NET, formularios Windows Forms,…). Como vemos, para añadir todos los controles hijos nos basta con añadir tblContenedor que es la tabla maestra que contiene las tablas auxiliares utilizadas que a su vez contienen los controles necesarios para visualizar los datos de un user profile.

this.Controls.Add(this.tblContenedor);

 

Sobreescribir el método Render()

Una vez que ya tenemos creados los controles hijos y añadidos a la web part, necesitamos que estos se visualicen. Se consigue sobreescribiendo el método Render() de la web part que nos permite justamente eso: renderizar los controles hijos de la web part de manera que al final los visualicemos de manera transparente como controles web típicos (y que nos devuelve el servidor web).

        protected override void Render(HtmlTextWriter writer)

        {

 

            if (dtData.Rows.Count > 0)

            {

 

                if (this.rdbListaEmpleados.SelectedIndex == 0)

                {

                    this.tblDetalleEmpleado.Rows.Clear();

                    this.rdbListaEmpleados_SelectedIndexChanged(this.rdbListaEmpleados, null);

                }

                this.tblContenedor.RenderControl(writer);

            }

            else

            {

                if (this.lblErrorProducido.Text == "")

                {

                    writer.Write("<b> El directorio de empleados está vacio o no cargado </>");

                }

                else

                {

                    this.lblErrorProducido.RenderControl(writer);

                }

 

            }

        }

Como vemos, el renderizado efectivo de los controles de la web part se realiza en la línea this.tblContenedor.RenderControl(writer). Es decir, el método RenderControl de nuestro control principal es el que se encarga de hacer dicho renderizado a través de un objeto de tipo HtmlTextWriter.

Manejador del objeto RadioButtonList()

Finalmente, sólo nos queda incluir el código del manejador para el evento SeletedIndexChangeg() del objeto rdbListaEmpleados. En este código es dónde se construirá, para cada user profile seleccionado, la ficha de detalle de un usuario. Una muestra de cómo se construye dicha ficha de detalle es el siguiente listado:

foreach (DataRow dr in dtData.Rows)

            {

                //Verificamos la opción elegida por el usuario

                if (this.rdbListaEmpleados.SelectedItem.Value == dr[ID_PROFILE].ToString())

                {

                    //Nombre

                    tblRow = new TableRow();

                    tblCell = new TableCell();

                    tblCell.Text = ETIQUETA1_PROFILE;

                    tblRow.Cells.Add(tblCell);

                    tblCell = new TableCell();

                    tblCell.Text = dr[CAMPO1_PROFILE].ToString();

                    //tblCell.BackColor = System.Drawing.Color.LightSkyBlue;

                    tblRow.Cells.Add(tblCell);

                    this.tblDetalleEmpleado.Rows.Add(tblRow);

 

                  

 

                                        //Fotografía

                    if (dr[CAMPO8_PROFILE].ToString() != "")

                    {

                        tblRow = new TableRow();

                        tblCell = new TableCell();

 

                        tblRow.Cells.Add(tblCell);

                        tblCell = new TableCell();

 

                        imgFotografia = new System.Web.UI.WebControls.Image();

                        imgFotografia.ImageUrl = dr[CAMPO8_PROFILE].ToString();

                        tblCell.Controls.Add(imgFotografia);

 

                        tblCell.Controls.Add(imgFotografia);

                        tblRow.Cells.Add(tblCell);

                    }

 

                    //Lo añadimos todo a la tabla!

 

                    this.tblDetalleEmpleado.Rows.Add(tblRow);

                }

            }

        }

Como vemos, construir la ficha de detalle del usuario seleccionado es una tarea sencilla. No tenemos más que comprobar cuál es el elemento seleccionado por el usuario y a partir de eta comprobación construir la ficha de detalle del empleado que estará contenida en la tabla tblDetalleempleado.

Despliegue y uso de la web part

Una vez que hemos codificado las distintas partes de la web part y tras comprobar que todo compila bien, procedemos a desplegar la web part. En este caso, y gracias a las extensiones de WSS 3.0 para Visual Studio, el despliegue es realmente sencillo puesto que se realiza de manera automática a través de la opción Implementar Solución que tenemos disponible en Generar -> Implementar Solución. El detalle de lo que se hace en este proceso de implementación ya lo comentamos en un post previo, por lo que os remito a ese post.

Ya sólo nos falta asegurar que la web part está desplegada en todos los sitios que nos interesa a través del Administrador de Soluciones de la administración central de MOSS:

Tras comprobar que la feature correspondiente a la web part está activada, ya podemos utilizar la web part en los sitios de MOSS dónde la hayamos implementado (ya sabéis, Configuración del sitio -> Características del sitio -> Características de la colección de sitios).

Sin más, esto es lo que os quería contar sobre los user profiles de MOSS. La verdad es que el tema es chulo, aunque al principio nos dio algún que otro quebradero de cabeza tanto listar los user profiles como visualizarlos del modo requerido. Por supuesto, esta web part es muy sencilla y se puede mejorar mucho ( a ver si alguien se anima). Os dejo el código de la web part aquí.

Published 18/6/2007 12:04 por Juan Carlos González Martín

Archivado en:
Comparte este post:

Comentarios

# re: MOSS: Leyendo los user profiles@ Friday, June 29, 2007 11:22 AM

Un excelente artículo, Juan Carlos.

Sin embargo tengo una duda: Quiero rescatar los user profiles ya no a nivel de web parts, o búsquedas, sino para tratar esos parámetros de usuario dentro de workflows generados con Designer. En concreto necesito expresar que si un usuario pertenece a un departamento concreto, tenga un validador diferente a si es de otro departamento (cada departamento tiene un validador). Pero designer, en su condicional "Creado Por", aunque deja seleccionar grupos, no mira si el usuario que ha generado el elemento de la lista pertenece al grupo seleccionado, solo compara los literales y ve que "Administradores != intranet\juan".

Por ello intenté seguir el segundo método que comentas y atacar el UserProfile.asmx desde InfoPath, el problema es que no deja publicar el formulario si no tiene un certificado digital de confianza...

Mi pregunta es: ¿Cómo puedo ver el "Departamento" al que pertenece el usuario que genera un formulario para tratar ese campo en el flujo de trabajo? He pensado en generar un acceso de datos en Designer, pero no sé en que tabla del SQLServer se guardan los user profiles, o en hacer un BDC que ataque a esa tabla de la BD... ¿Alguna sugerencia? No quisiera entrar en Visual Studio, ya que entonces todo se complica en exceso.

Gracias, un saludo!

Ignasi Tebé.

Ignasi Tebé

# re: MOSS: Leyendo los user profiles@ Friday, June 29, 2007 12:01 PM

Hola Ignasi,

Para poder utilizar el departamento tienes que tener incluida esta columna en la librería de formularios o en la lista dónde estés guardando el formulario. Si utilizas la opción de Infopath (Aqui te hago una pregunta, ¿has conseguido que se recupere el departamento en el preview del formulario antes de publicarlo? Si lo has conseguido con la llamada al servicio web, veo más factible que consigas publicar el formulario en tu sitio de MOSS, que por lo que comentas te falla ¿estás utilizando https en el sitio MOSS dónde quieres publicar? Si no lo estás utilizando, en principio debería funcionarte la publicación, y si lo usas también porque Infopath no imponen ninguna restricción en este sentido (por lo que yo se).

En definitiva, la mejor opción es que consigas tener la información del departamento en el formulario bien porque la lees del user profile o utilizas una lista auxiliar en la que guardes esa información. Esta es una alternativa para tu segunda pregunta, utilizando la publicación.

No te recomiendo que intentes hacer una acceso a datos en la BD de contenidos de MOSS, piensa que la idea de Sharepoint es que trabajemos con listas y elementos de listas, en ningún caso a nivel de la BD. Por el mismo motivo, no aplica el que te crees un BDC para esto, el BDC está pensado para atacar a sistemas backend fuera de MOSS, y además implica que tengas las herramientas (BDC Meta Man) o conocimientos (XML) necesarios para construirlos.

Si tienes más dudas, aqui estamos para echarte un cable

Un saludo

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Monday, July 2, 2007 9:32 AM

Buenos dias Juan Carlos

Quizás el problema venga porque mi formulario se publica via web (con form services)y eso limita las opciones del mismo. Pero en este proyecto no hay licencias de infopath para todas las máquinas cliente, así que ha de ser via web...

Mi servidor no es https, es un acceso http normal.

Yo también pienso que la mejor manera es con Infopath, pero mi desesperación viene cuando consigo verlo todo correctamente en la vista previa, pero no consigo publicar el formulario en la biblioteca. Anteriormente esa biblioteca tenía el mismo formulario sin el acceso a datos del userprofiles y no daba problema ninguno, pero en el momento que le configuro el campo Departamento y muestro los datos con GetUserProfileByName (todo ok hasta aquí), necesito habilitar en Opciones de formulario-->Seguridad y confianza la casilla de "plena confianza" y para ello me pide firmar digitalmente el formulario.

Si la firma digital no es reconocida, te obliga, en el momento de la publicación a guardarlo en un directorio (no deja publicarlo directamente como plantilla de la lista).

He intentado cargar la plantilla en la lista directamente sin infopath, pero entonces no la detecta como form services e intenta abrir el formulario con infopath en un cliente que no tiene dicho programa.

Lo de la lista auxiliar que comentas, ¿te refieres a crear una lista usuario-departamento de forma manual? eso implicaría un mantenimiento muy engorroso, no? En una empresa donde hay bajas y altas contínuas, volvería loco al admninistrador del sistema. Si hubiera un proceso para automatizar eso... Lo ideal es leer del userprofile del AD, pero no se como llegar a esos datos directamente en las listas de SharePoint...

No acabo de entender la filosofía de infopath, debería dejarme publicar el formulario que yo quiera, bajo mi responsabilidad, sin obligarme a firmalo digitalmente con una firma reconocida!

Gracias por tu tiempo, Juan Carlos.

Ignasi Tebé

# re: MOSS: Leyendo los user profiles@ Monday, July 2, 2007 10:10 AM

Hola Ignasi,

Íbamos a hacer justo esa prueba para contestarte, pero ya las hecho tú, asique perfecto. En principio, la llamada a un sevicio web de MOSS desde Infopath no implica que tengas que marcar el formulario como confianza plena, sino que como muy bien has hecho basta con que marques Dominio. En principio, salvo que alguien me corrija, esta opción no te dará problemas de seguridad.

Enhorabuena!

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Monday, July 2, 2007 10:47 AM

Muchas gracias Juan Carlos, para mí ha sido una revolución encontrar vuestra web. Los artículos de "recopilación de enlaces interesantes" son geniales y me han abierto un mundo de blogs sobre MOSS 2007 im-presionantes.

Hasta ahora solo miraba en un par de webs y en muchos desafíos estaba más solo que la una, pero la comunidad MOSS 2007 crece de forma apabullante, y a dia de hoy existen grandes referencias como la vuestra.

Sin mas os animo a seguir en vuestra línea, inspiradora para muchas hormiguitas como yo.

Ignasi Tebé

# re: MOSS: Leyendo los user profiles@ Monday, July 2, 2007 11:10 AM

Gracias a tí, los comentarios que ponéis la gente que lee habitualmente Geeks y las cuestiones que nos planteáis nos animan a seguir contando cosas interesantes.

Un saludo

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Thursday, July 19, 2007 12:20 PM

Hola,

Estoy intentando crear un webpart que muester información de usuario de forma aleatoria siguiente el ejemplo mostrado en este post. La cuestión es el desarrollo me funciona perfectamente con el usuario administrador. Sin embargo, salta una excepción al acceder con otros usuarios.

La línea de código que da problemas es la siguiente:

For Each upro As UserProfile In upManager

//...

Next

La excepción:

System.UnauthorizedAccessException: Access Denied: Only an administrator may enumerate through all user profiles

Hay alguna maner de solucionar este problema?

Un Saludo,

Gracias,

Aitor

# re: MOSS: Leyendo los user profiles@ Thursday, July 19, 2007 12:51 PM

Hola Aitor,

Lo que te está pasando es que estás realizando una acción que requiere permisos de usuario con ciertos privilegios. Para evitarte este problema, lo que tienes que hacer es una elevación de privilegios en el código en el que lees los profiles (con tu comentario me acabo de dar cuenta que en el ejemplo subido no lo hice). Simplemente sería algo tal que así:

SPSecurity.RunWithElevatedPrivileges(delegate()

           {

               // Obtener un contexto de seguridad                

               using (SPControl.GetContextSite(this.Context))

               {

'Código lectura de los user profiles

...

}

     };

Con esto se te debería solucionar el problema que comentas.

Un saludo

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Thursday, July 19, 2007 3:32 PM

Hola,

He probado la solución que me has propuesto, de la siguiente forma:

Public Sub getUsuarioElevado()

       Dim i As Integer

       Dim us2 As New Usuario

       Using spsitio = SPControl.GetContextSite(Me.Context)

           Dim scContexto As ServerContext = ServerContext.GetContext(spsitio)

           Dim upManager As UserProfileManager = New UserProfileManager(scContexto)

           i = Int(Rnd() * (upManager.Count - 1))

           Dim aGuid As New ArrayList

           For Each upro As UserProfile In upManager

               aGuid.Add(upro.ID)

           Next

           Dim up As UserProfile = upManager.GetUserProfile(aGuid(i))

           us2.nombre = up("AccountName").Value.ToString()

           Try

               us2.urlImagen = up("PictureURL").Value.ToString

           Catch ex As Exception

               us2.urlImagen = String.Empty

           End Try

           Try

               us2.email = up("workEmail").Value.ToString

           Catch ex As Exception

               us2.email = String.Empty

           End Try

           Me.us = us2

       End Using

   End Sub

Llamo a este procedimiento de la siguiente forma:

Dim MiCodigoElevado As SPSecurity.CodeToRunElevated = New SPSecurity.CodeToRunElevated(AddressOf Me.getUsuarioElevado)

Ahora bien, sigue dándome el mismo error. Solamente permite acceder al atributo "count" de la clase "UserProfileManager" si eres administrador. De la misma forma solamente permite recorrer la lista "UserProfileManager" si eres administrador.

No sé si se me esacapa algo.

Un Saludo,

Gracias,

Aitor

# re: MOSS: Leyendo los user profiles@ Thursday, July 19, 2007 5:23 PM

Hola!

El problema es que así no estás haciendo la elevación de privilegios de forma corecta. Tienes que utilizar SPSecurity.RunWithElevatedPrivileges(delegate()...fijate en como te lo he puesto para C#. En VB.NET es similar, te paso la referencia y el ejemplo que ponen en MSDN:

msdn2.microsoft.com/.../microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx

Declaración:

Public Shared Sub RunWithElevatedPrivileges ( _

secureCode As CodeToRunElevated _

)

Uso:

Dim secureCode As CodeToRunElevated

SPSecurity.RunWithElevatedPrivileges(secureCode)

COmo yo lo he hecho en C# es justo con un método anónimo que también tienes en VB.NET.

Espero que con esta info. puedas resolver el problema.

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Monday, July 23, 2007 5:28 PM

Hola,

Me he dado cuenta que en el comentario anterior no he puesto como llamaba al método RunWithElevatedPrivileges:

Dim MiCodigoElevado As CodeToRunElevated = New CodeToRunElevated(AddressOf getUsuarioElevado)

RunWithElevatedPrivileges(MiCodigoElevado)

El método donde quiero establecer permisos de administrador es el mismo que expliqué en el anterior comentario. He seguido las pautas establecidas por MSDN y por siguiente artículo:

msdn2.microsoft.com/.../bb466220.aspx

Aún así, no logro realizar correctamente la impersonalización en VB .NET. La única solución que se me ocurría ha sido programar el webpart en C#, pero también falla.

Un Saludo,

Gracias,

Aitor

# re: MOSS: Leyendo los user profiles@ Monday, July 23, 2007 6:49 PM

Hola Aitor,

El viernes estuve revisando y probando la web part con un usuario pertenciente al grupo de lectores de un sitio de MOSS y puede comprobar que efectivamente tenías razón y que ni con elevación de privilegios se consiguen leer los user profiles almacenados en el profile store. He estado buecenado por el SDK de MOSS y no contiene ninguna mención a esta situación, lo que me parece sorprendente pues puede ser un requerimiento usual. He encontrado varios enlaces en los que explican como se podría resolver el problema, pero de momento no he conseguido que se listen los user profiles aún consiguiendo que la cuenta que accede a los mismos es NETWORK SERVICE que si tiene permisos para acceder a los profiles. Si te parece, pásame tu e-mail personal y a ver si conseguimos sacar algo en claro de esto. El mio es jcgonzalez@ciin.es. Aqui te paso los links que he estado mirando y en los que tratan el problema:

• Lo que he intentado el viernes es sharingpoint.blogspot.com/.../who-am-i-demystifying-sharepoint.html, y con esto conseguí que la entidad que accede y realiza todas las operaciones sea NETWORK SERVICE (Pablo lo vio conmigo el viernes)…pero sigue dando el mismo fallo…lo que me mosquea de este link es lo que pone al final: Of all the methods that are available for running code under an administrative context in SharePoint, this combination of impersonation and application domains is the only one that I’ve found works in every situation I’ve tried. Es decir, no me queda claro si de la forma que se expone en este artículo se está ejecutando el código como administrador en el contexto de sharepoint que parece que es la única forma de leer los profiles del objeto que mencionas.

• Linkados a este enlace hay otros en la que se hace lo mismo de otras formas más o menos complicadas pero que creo (salvo que Ángel cuando pueda echarle un ojo me diga lo contrario) llevan a lo mismo:

o www.lcbridge.nl/.../impersonation.htm, el problema de la solución de este link es que utilizan objetos que si dice Visual Stuido 2005 están obsoletos.

o www.bluedoglimited.com/.../ViewPost.aspx, esa es la forma que parece más compleja y que parece que lleva a lo mismo.

o Otro más: mindsharpblogs.com/.../467.aspx

Un saludo y gracias por tu comentarios

JC

p.d: a ver si conseguimos que funcione.

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Thursday, August 9, 2007 12:56 PM

A mi me pasaba lo mismo, pero lo he podido resolver asignando permisos a la cuenta de Application Pool. En mi blog explico el proceso.

edinkapic.blogspot.com/.../enumerating-user-profiles.html

Un saludo!

Edin

# re: MOSS: Leyendo los user profiles@ Thursday, August 9, 2007 1:10 PM

Aquí lo que debeis revisar es los permisos que tiene el usuario con el que se elevan los permisos (AppPool), para configurarlo en el SSP.

- Manage user profiles

- Use Personal Features

- Read profiles

La consideración a incluir es que la aplicación que corra con dichas credenciales, sea voluntaria o 'involuntariamente' tendrá esos privilegios.

De ahí por ejemplo el comentario del Best Practice de emplear cuentas distintas para el CentralAdmin y cualquier sitio.

un saludo

carlos

# re: MOSS: Leyendo los user profiles@ Thursday, August 9, 2007 1:13 PM

No te había visto (esta caché...)

Qué bueno eres escribiendo Edin ;)

Carlos

# re: MOSS: Leyendo los user profiles@ Friday, August 10, 2007 10:02 AM

Hola a los dos!

Gracias por los comentarios, la verdad es que el asunto de leer los profiles nos ha dado muchos quebraderos de cabeza...al final opte por replicarlos en una lista de contactos de WSS 3.0 y ahí lo había dejado, pero a la vuelta de mis vacaciones probaremos lo que nos comentas para ver si conseguimos leer los profiles sin tener que duplicarlos. Muchas gracias Edim y gracias también Carlos.

JC

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Monday, July 28, 2008 6:37 PM

Hola, muy buen post, gracias por la información, pero quisiera hacer una pequeña pergunta: si yo quisiera que MOSS leyera datos desde un BDC para colocarlos como datos de los perfiles de usuarios, ¿cómo se realiza esta acción? ya tengo escrito el BDC, el cual tiene un solo filtro el que de alguna forma pretendo que haga referencia a la propiedad account name de MOSS. Por ejemplo, tengo varios usuarios que no tienen valores en la propiedad WorkEmail debido a que no estan puestas en el AD, y mediante el BDC pretendo validar que la cuenta de usuario o Account Name, donde ésta sea igual a la que existe en la conexión con el BDC me coloque el correo que se encuentre en ese registro.

De antemano gracias por sus respuestas.

Atte

Alberto

Alberto

# re: MOSS: Leyendo los user profiles@ Tuesday, July 29, 2008 8:27 AM

Hola Alberto,

Para hacer lo que me comentas, no entiendo muy bien que es lo que quieres hacer...explicame de forma más precisa que necesitas porque tu pregunta es un poco liosa.

Un saludo

JC's

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Tuesday, July 29, 2008 3:01 PM

Ya... a ver si ahora me explico bien... en mis usuarios de MOSS no están puestos los correos electrónicos, sólo los nombres de usuarios y de dominio, entonces yo desde una base de datos que tengo en SQL 2005 quiero extraer los correos de los usuarios mediante la conexión con BDC. La idea es que en la base de datos hay un campo que guarda los nombres de usuario de dominio, y en base a este campo saber a qué usuario le corresponde cada correo... quisiera saber paso a paso cómo se hace eso por favor... no sé si me expliqué bien...

De antemano Gracias

Alberto

Alberto

# re: MOSS: Leyendo los user profiles@ Tuesday, July 29, 2008 10:25 PM

Buenas Alberto,

Me imaginaba que ibas por ahí. Yo lo que haría (intentaré hacer una prueba de concepto,pero no te prometo nada en cuanto a cuando la tendré acabada) es crear un servicio que te lea por una parte el contenedor de los profiles (la cuenta de usuario), busque la cuenta de e-mail correspondiente en la BD SQL Server y a continuación actualice la propieda de e-mail...vamos, que necesitas programación. Desde mi punto de vista, el BDC no lo necesitas para lo que quieres hacer.

Un saludo

JC's

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Wednesday, July 30, 2008 3:20 PM

Gracias por la respuesta, Carlos, entiendo lo que me quieres decir, el problema es que soy algo novato en esto de MOSS, ¿me podrías orientar un poco en cuanto a la solución de crear un servicio que haga lo que yo deseo?

De antemano muchas gracias por todo, y disculpe que lo moleste.

Atte.

Alberto

# MOSS: C&oacute;mo actualizar los User Profiles! &laquo; Pasi??n por la tecnolog??a&#8230;@ Friday, August 1, 2008 12:10 AM

PingBack desde  MOSS: C&oacute;mo actualizar los User Profiles! &laquo; Pasi??n por la tecnolog??a&#8230;

MOSS: Cómo actualizar los User Profiles! « Pasi??n por la tecnolog??a…

# re: MOSS: Leyendo los user profiles@ Friday, August 1, 2008 8:24 AM

Hola Alberto,

Ya tienes la solución en: geeks.ms/.../moss-c-243-mo-actualizar-los-user-profiles.aspx

Un saludo

JC's

Juan Carlos González Martín

# re: MOSS: Leyendo los user profiles@ Thursday, January 15, 2009 7:17 PM

Resolution for "Unauthorized Access" exception is here

dotnetdreamer.wordpress.com/.../enumerating-sharepoint-user-profiles-access-denied-exception

Ramprasad