Número #27 de CompartiMOSS y nueva colaboración

Muy buenas a todos,

El pasado lunes se publicó un nuevo número de la revista CompartiMOSS con contenido muy interesante sobre SharePoint, Office 365 y Azure. La revista está haciendo de forma muy natural una transición muy interesante hacia incluir contenido relacionado con Office 365 y Azure además de continuar con la temática de SharePoint.

A continuación os dejo un índice de todos los artículos interesantes que podréis encontrar en el número que acaba de salir:

  • Configurando Azure Directory Services para Office365 por Darwin Castro Marín
  • ENMARCHA: Un Framework Open Source para agilizar el desarrollo en SharePoint por Adrian Diaz Cervera
  • Entrevista Enrique Rhenals Bárcenas por Enrique Rhenals Bárcenas
  • Usando Azure Search en soluciones de búsqueda para Office 365 por José Carlos Rodríguez Avilés
  • ¿Es Project Server / Online realmente multiidioma? por José Rafael García
  • ¿Qué son las PowerApps de Microsoft? – Creando nuestra primera aplicación por Sergio Hernandez Mancebo
  • Conectores para Grupos de Office 365 por Ruben Toribio
  • Conociendo a MinRole de SharePoint 2016 por Miguel Tabera Pacheco
  • Introducción al PnP Program y Provisioning framework por Luis Mañez
  • Particularidades de la instalación de una Granja de varios servidores de SharePoint 2016 por Juan Carlos Gonzalez Martin
  • SharePoint 2013 Client Side Rendering en detalle por José Quinto Zamora
  • StratusForms – ¿Adios InfoPath? por Luis Molina
  • ¿InfoPath se muere? por Gonzalo Marcos Ansoain
  • Integración de Powershell local con Powershell de Azure por Enrique Rhenals Bárcenas

Como podéis ver, de nuevo, la revista me ha dado la oportunidad de colaborar con ellos, en esta ocasión con un artículo relacionado con Azure Search y Office 365 que espero que disfrutéis. Es un tema que me ha resultado muy interesante desde siempre y que he tenido la oportunidad de conocer y quería compartir con todos. De hecho en el blog podréis encontrar artículos recientes sobre este tema.

Os dejo el enlace de la revista para que podáis acceder todos aquellos que os resulte interesante:

http://www.compartimoss.com/Revistas/Numero-27

De nuevo muchas gracias a la revista por permitirme colaborar con ellos y espero que os guste, os animo a leer el contenido de este número, es muy interesante y aprenderéis muchísimo.

Saludos

 

Autenticación app-only para usar la API Microsoft Graph en webjobs de Azure

Muy buenas a todos

En entradas anteriores, hemos visto cómo empezar a trabajar con el servicio de búsqueda de Azure, creando los índices. Dentro de mi objetivo a la hora de trabajar con este servicio, estaba el de indexar contenido de Office 365 usando la API Microsoft Graph por medio de webjobs. Y es aquí donde entra lo que os quiero contar hoy.

El flujo habitual de autenticación para usar la API Microsoft Graph en nuestras aplicaciones está basado en el protocolo OAuth2. Este protocolo parte de un token que hace una delegación de una serie de permisos específicos para un usuario concreto. Para obtener este token, es necesario que el usuario se identifique en Office 365 al menos una vez, por lo que tiene que introducir sus credenciales en una pantalla de autenticación que se muestra en pantalla.

Sin embargo, hay una serie de aplicaciones en las que este flujo de autenticación no es posible, aplicaciones que ejecutan tareas en background y en las que no hay un usuario como pueden ser los webjobs. Para este tipo de aplicaciones, el protocolo OAuth2 proporcionar un flujo adicional de autenticación y es el que vamos a usar para acceder a la API de Microsoft Graph en una aplicación que se va a ejecutar en un webjob de Azure. Podemos usar este flujo de autenticación, de momento, para obtener acceso a las API de contactos, mail y calendario. He estado probando y para OneDrive aún no está soportado.

Antes de nada, os voy a dejar los enlaces donde he encontrado toda la información y el tutorial para poder configurar la aplicación y todo lo que hay que hacer en Azure para que funcione correctamente.

http://www.eliostruyf.com/building-daemon-or-service-app-with-the-microsoft-graph-api/

http://blogs.msdn.com/b/exchangedev/archive/2015/01/21/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx

Creando los permisos para la aplicación en AAD

El primer paso que tenemos daremos será configurar los permisos de nuestra aplicación en Azure Active Directory.

1.- Accedemos a Azure, el portal clásico y vamos a la sección de Azure Active Directory. Una vez ahí nos vamos al apartado de aplicaciones, donde añadiremos una nueva aplicación.

Captura de pantalla 2016-01-24 a las 16.28.51

2.- Seleccionamos la opción de “Agregar una aplicación que mi organización está desarrollando” y de tipo “Aplicación Web y/o API Web” ya que la otra opción no soporta el tipo de autenticación app-only que vamos a configurar.

Captura de pantalla 2016-01-24 a las 16.29.04

Captura de pantalla 2016-01-24 a las 16.29.28

3.- Indicamos la URL de inicio de sesión y la URI de la aplicación. El primero de los dos valores, no es importante, en este caso hemos añadido la url donde el webjob estará alojado.

Captura de pantalla 2016-01-24 a las 16.30.49

4.- Vamos a la nueva aplicación que hemos añadido y en la pestaña “Configuración”, vamos a la parte final, de permisos, ahí añadimos permisos para Microsoft Graph.

Captura de pantalla 2016-01-24 a las 16.31.30

Captura de pantalla 2016-01-24 a las 16.31.42

5.- Una vez añadidos, tenemos que indicar en el desplegable de “Permisos de la Aplicación” (ya que los permisos los vamos a conceder directamente a la aplicación), los servicios para los que tendrá permisos.

Captura de pantalla 2016-01-24 a las 16.31.57

6.- Una vez terminado pulsamos Guardar.

Creando y configurando los certificados

A continuación necesitamos generar los certificados y configurarlos en nuestra aplicación web (que también tendremos que crear) y en la aplicación que acabamos de crear en nuestro AAD.

1.- En primer lugar, abrimos la consola de comandos y creamos el certificado, sustituyendo Tenant y AppName por los valores que correspondan

makecert -r -pe -n “CN=Tenant AppName Cert” -b 11/25/2015 -e 11/25/2017 -ss my -len 2048

2.- A continuación, vamos a exportar dicho certificado como PFX y CER. Para ello primero abrimos el Microsoft Management Console (mmc.exe).

3.- Una vez aquí, vamos a archivo->Agregar o quitar complemento y ahí añadimos la opción certificados.

cer1

4.- A continuación, buscamos el certificado que acabamos de crear y hacemos click sobre el botón derecho del mismo y seleccionamos Todas las tareas->exportar

cer3

Tenemos dos opciones de exportación, “Exportar la clave privada” y “No exportar la clave privada”, ejecutaremos la exportación dos veces y completaremos el asistente para cada una de éstas opciones, generando los dos certificados.

5.- Ahora, volvemos nuevamente a la aplicación que hemos creado en Azure Active Directory para configurar el certificado en la misma. Esto no se puede hacer a través de una interfaz gráfica, por lo que habrá que hacerlo modificando el manifest. Para ello, lo primero que debemos hacer es recuperar las claves del certificado CER que hemos obtenido, esto lo podemos hacer por medio del siguiente script de powershell:


$certPath = Read-Host "Enter certificate path (.cer)"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($certPath)
$rawCert = $cert.GetRawCertData()
$base64Cert = [System.Convert]::ToBase64String($rawCert)
$rawCertHash = $cert.GetCertHash()
$base64CertHash = [System.Convert]::ToBase64String($rawCertHash)
$KeyId = [System.Guid]::NewGuid().ToString()
Write-Host "base64Cert:" $base64Cert
Write-Host "base64CertHash:" $base64CertHash
Write-Host "KeyId:" $KeyId

Este script nos devuelve las tres claves que nos hacen falta.

6.- Ahora, descargamos el manifest de la aplicación:

Captura de pantalla 2016-01-24 a las 17.46.09

Captura de pantalla 2016-01-24 a las 17.46.25

7.- Y sustituimos la siguiente cadena:


"keyCredentials": []

por


"keyCredentials": [
 {
 "customKeyIdentifier": "base64CertHash",
 "keyId": "KeyId",
 "type": "AsymmetricX509Cert",
 "usage": "Verify",
 "value": "base64Cert"
 }
],

Sustituyendo los valores “base64CertHash”, “KeyId” y “base64Cert”, por la cadena correspondiente obtenida de la ejecución del script powershell anterior.

8.- Ahora tenemos que volver a cargar el manifest modificado en la aplicación con lo que habremos terminado de configurar los permisos de nuestra app en Azure Active Directory.

9.- A continuación, creamos una aplicación web de Azure y cargamos el certificado PFX en la misma.

Captura de pantalla 2016-01-24 a las 17.57.36

Es necesario escalar la aplicación web a nivel básico

Captura de pantalla 2016-01-24 a las 17.58.28

En la pestaña configuración de la aplicación web, hacemos click en Cargar un certificado

Captura de pantalla 2016-01-24 a las 17.59.15

Captura de pantalla 2016-01-24 a las 18.01.35

En la sección de configuración de aplicación, añadimos el valor WEBSITE_LOAD_CERTIFICATES con la huella digital que hemos obtenido al cargar el certificado.

Captura de pantalla 2016-01-24 a las 18.07.42

Y por fin, habremos configurado los certificados en Azure. Ahora no solo nos queda publicar y probar el WebJobs.

Creando y publicando el webjob en Azure 

Vamos a crear una nueva aplicación de consola con el código del WebJob que vamos a publicar.

Para esta aplicación hay que añadir las siguientes referencias:

  • System.Configuration

Y Añadir a través de Nuget la librería ADAL y RestSharp.

Además en el app.config, debemos añadir las siguientes propiedades:


 <appSettings>;
 <add key="GraphUrl" value="https://graph.microsoft.com"/>;
 <add key="ClientId" value="clientidaad"/>;
 <add key="Thumbprint" value="thumbprint"/>;
 <add key="Authority" value="https://login.windows.net/tenant.onmicrosoft.com/"/>;
 </appSettings>;

Debemos de sustituir el clientidaad por el ClientId de la aplicación que hemos creado en el Azure Active Directory, el valor de thumbprint por la huella obtenida al cargar el certificado en la aplicación web y por último sustituir el valor tenant por el nombre de nuestra organización.

Lo que nos queda ahora, es el código de la aplicación de consola de ejemplo, que es el siguiente:


class Program
 {
 private static readonly string GraphUrl = ConfigurationManager.AppSettings["GraphUrl"];
 private static readonly string ClientId = ConfigurationManager.AppSettings["ClientId"];
 private static readonly string Authority = ConfigurationManager.AppSettings["Authority"];
 private static readonly string Thumbprint = ConfigurationManager.AppSettings["Thumbprint"];

static void Main(string[] args)
 {
 //&nbsp;Recuperar el certificado
 var certificate = GetCertificate();

//&nbsp;Recuperar el token de acceso
 var token = GetAccessToken(certificate);

//&nbsp;Obtener los contactos
 var client = new RestClient(GraphUrl);
 var request = new RestRequest("/v1.0/users/&lt;userid&gt;/contacts", Method.GET);
 request.AddHeader("Authorization", "Bearer " + token.Result);
 request.AddHeader("Content-Type", "application/json");
 request.AddHeader("Accept", "application/json");

var response = client.Execute(request);
 var content = response.Content;

Console.WriteLine(content);

}

private static X509Certificate2 GetCertificate()
 {
 X509Certificate2 certificate = null;
 var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
 certStore.Open(OpenFlags.ReadOnly);
 var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, Thumbprint, false);

 if (certCollection.Count &gt; 0)
 {
 certificate = certCollection[0];
 }
 certStore.Close();
 return certificate;
 }

private static async Task&lt;string&gt; GetAccessToken(X509Certificate2 certificate)
 {
 var authenticationContext = new AuthenticationContext(Authority, false);
 var cac = new ClientAssertionCertificate(ClientId, certificate);
 var authenticationResult = await authenticationContext.AcquireTokenAsync(GraphUrl, cac);
 return authenticationResult.AccessToken;
 }
 }

El último paso es publicar la aplicación como un WebJob de Azure. Para ello, haciendo click en botón derecho sobre el proyecto de consola, seleccionaremos la opción Publish as Azure WebJob

public1

A continuación, indicamos la planificación del WebJob:

public2

Seleccionamos la aplicación web a la que queremos asociar el WebJob:

public3

Por último publicamos el WebJob.

public4

Y esto es todo, podemos probarlo ejecutando una vez el WebJob en Azure y ver que al final, se devuelven los contactos del usuario que le hemos indicado.

Captura de pantalla 2016-01-24 a las 19.05.09

Hasta aquí el post de hoy. Con lo que hemos visto en este post, podemos consumir información de Office 365 desde aplicaciones en background que no nos permiten usar el flujo habitual de autenticación del protocolo OAuth2.

Espero que os haya resultado interesante, en futuros post usaremos todo lo que hemos visto hoy para indexar contenido de Office 365 en Azure Search a través de un WebJob como el que hemos creado hoy.

Hasta la próxima

 

 

Versión 1.0 de la API de Office 365: Microsoft Graph

Muy buenas a todos.

Hace unos meses, desde Microsoft se lanzó lo que se denominó “Office 365 unified API” en su versión preview. El objetivo, era agrupar en un mismo endpoint, todas las APIs que permitieran el acceso a los distintos servicios en la nube que se ofrecen y hacerlo siguiendo el estándar de la industria, por medio de una API REST. Esto supuso un importante avance en la forma en que se podía acceder a los servicios en la nube. Sobre todo esto hablé en una entrada del blog, en la que os contaba cómo usar esta API, que os dejo a continuación:

La nueva API de Office 365 Unificada

Lo que os quiero contar hoy, es que recientemente, se ha publicado la v1.0 de esta API que desde ahora pasará a llamarse Microsoft Graph y que incluye una serie de servicios que dejan de estar en Preview y que según nos dicen pueden ya ser usados con todas las garantías en nuestros proyectos finales.

Today-at-Connect-1

Como dice en la página principal de la documentación y de la que os dejo el enlace más adelante:

One endpoint to rule them all
No more obtaining separate tokens for different services or calling a different endpoint for each API.
Leverage the power of Microsoft Graph, a unified API endpoint, for accessing data, intelligence, and insights coming from the Microsoft cloud.

Más que entrar en detalle en cómo podemos usarla, quería dejaros una serie de enlaces interesantes e información sobre la misma, ya que la forma de uso sigue siendo muy similar a la que ya os comenté en el artículo al que me he referido anteriormente.

Para usar esta primera versión, lo único que tendremos que hacer es cambiar el endpoint. Si antes accedíamos a la API a través del siguiente enlace:

https://graph.microsoft.com/beta

Ahora lo haremos a través de este:

https://graph.microsoft.com/v1.0

La versión beta sigue estando disponible, y es donde encontraremos todo el conjunto de opciones disponibles, los que ya han pasado a la primera versión, y los que aún se encuentran en preview. Evidentemente se puede seguir usando esta preview, aunque desde Microsoft no recomiendan hacerlo para proyectos finales (como cualquier versión de estas características). En el siguiente enlace podéis ver los distintos servicios que se ofrecen en una versión y otra:

http://graph.microsoft.io/docs

Y aquí entra otro de los motivos que más me ha sorprendido, y es la cantidad de documentación que Microsoft se ha encargado de generar para que la adopción de esta API sea relativamente rápida. Y  no es que desde Microsoft no se genere documentación suficiente sobre cómo usar sus SDK´s o todo lo que ponen a disposición de los desarrolladores, es que para Microsoft Graph lo han hecho de una forma ligeramente diferente, que a mi particularmente me gusta (me recuerda más a como encontramos la documentación para la cantidad de proyectos que tenemos disponible para desarrolladores hoy en día, por decirlo de alguna forma, más actual).

Toda la información sobre esta API la podemos encontrar en:

http://graph.microsoft.io

En Channel 9 tenéis este vídeo, muy recomendable, donde podéis ver en 11 minutos bastante información sobre Microsoft Graph:

https://channel9.msdn.com/Events/Visual-Studio/Connect-event-2015/301

Si queréis testear y probar los endpoint, encontraréis a vuestra disposición este enlace:

https://graphexplorer2.azurewebsites.net/

Y bueno, os dejo, una serie de enlaces más para que podáis encontrar más información:

https://blogs.office.com/2015/11/18/today-at-connect-introducing-the-microsoft-graph/

http://dev.office.com/getting-started/office365apis

http://dev.office.com/chooseapiendpoint

Y esto es todo por hoy, espero que lo encontréis interesante y os animo a que le echéis un vistazo a toda la información que hay.

Un saludo a todos

Sharepoint-search: un componente Polymer para usar la búsqueda de SharePoint On-Line

Muy buenas a todos.

En una entrada anterior, os contaba cómo usar la búsqueda de SharePoint a través de su servicio API REST. El enlace ha dicha entrada es la siguiente:

Search Driven Development. Usando la API REST de SharePoint para el servicio de búsqueda

Al final de esta entrada os contaba que como objetivo, tenía el desarrollo de un componente Polymer que permitiera usar este servicio, algo que me resultaba muy útil e interesante. Después de varios días de trabajo, quería compartir con vosotros una primera “versión” de dicho componente. Aún queda trabajo por delante, pero ya hay un punto de partida funcional a partir del cual seguir trabajando.

El componente debía cumplir con los siguientes requisitos:

  • Permitir la posibilidad de usar refinadores.
  • Permitir la posibilidad de establecer opciones de ordenamiento.
  • Controlar la paginación y el número de resultados por página en los resultados de búsqueda.
  • Dar la posibilidad de estilar el contenido del componente en función de como se desee.

El componente “sharepoint-search” nos permite cubrir estos requisitos. Para usarlo, necesitaremos tener cargados los ficheros de Polymer y los propios del componente y utilizaremos la etiqueta de la siguiente manera:

<sharepoint-search tenant="organizer" clientid="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" refinement="author,size,created" ordination="size,created" pageElement="15">
</sharepoint-search>

Para que funcione correctamente, necesitaremos el clientID de una aplicación de Azure AD con los permisos para el servicio de búsqueda de SharePoint concedidos, y obviamente estar logado en nuestra aplicación contra esa aplicación de Azure AD, para ello podemos usar el componente para la autenticación que creé en una entrada anterior y seguir los correspondientes pasos para obtener el clientid:

Registrando una aplicación en Azure Active Directory

login-azuread: Un Componente Web con Polymer y Javascript ADAL

Además deberemos de configurar la aplicación de nuestra Azure AD para permitir el OAuth 2.0 implicit grant flow, lo haremos de la siguiente forma:

  • Acceder a la configuración de la aplicación de Azure AD correspondiente
  • Descargamos el manifiesto
  • Modificamos el parámetro oauth2AllowImplicitFlow dándole el valor true en lugar de false que tiene establecido inicialmente
  • Cargamos de nuevo el manifiesto modificado

El componente “sharepoint-search” permite configurar los siguientes parámetros:

  • tenant: Indicar el tenant al que nos queremos conectar
  • clientid: Clientid de la aplicación con los permisos adecuados
  • refinement: Propiedades para las cuales queremos obtener refinamiento
  • ordination: Propiedades por las que queremos hacer ordenación
  • pageElement: Número de elementos por página a mostrar

Una vez que lo añadimos, funciona como vemos a continuación.

sharepointsearchinit

sharepointsearchsearched

Por defecto, el componente nos muestra los resultados en una lista con el título del documento y la posibilidad de descargar el mismo. Aunque como se indica a continuación, en futuras mejoras, se trabajará en flexibilizar este aspecto del componente.

Os dejo el enlace a mi cuenta de GitHub donde podéis descargar el código del componente web y donde podréis encontrar información sobre cómo usarlo.

https://github.com/jcroav/sharepoint-search

Y esto es todo por hoy, este componente aún tiene áreas de mejora, a las que intentaré dedicarle tiempo en las próximas semanas. Os dejo algunas de las ideas:

  • El componente está pensado para que los resultados de búsqueda usen a su vez un subcomponente para ser mostrados, queda pendiente de desarrollar esa parte.
  • Completar el componente con la funcionalidad de sugerencias
  • Mejorar toda la parte de estilado
  • Refactorizar y trabajar sobre la optimiazación del código para hacer un componente más robusto

Como siempre, todo aquel que quiera colaborar, o quiera usar el componente que os he mostrado hoy para mejorarlo, es libre de hacerlo. El objetivo de estos desarrollos, a parte de para aprender a usar las funcionalidades de Office 365 y SharePoint On-Line, es contribuir a la comunidad.

Un saludo y espero que os sea útil

La nueva API de Office 365 Unificada

Buenas tardes a todos,

Esta semana desde Microsoft se lanzó la noticia de la aparición de una nueva API de Office 365 unificada, que busca facilitar y estandarizar todas las operaciones que se pueden realizar contra los servicios de Office 365 a través de su API, además de añadir nuevas opciones y servicios a la misma. Ayer tuve la oportunidad de echar un vistazo a esta API unificada y me pareció que mejora mucho la versión anterior y particularmente me gusta más esta línea que la que llevaba hasta ahora.

Hoy os voy a contar en qué consisten todas estas mejoras y enseñaros un ejemplo de cómo trabajar con ella que podréis comparar con un ejemplo que publiqué hace un tiempo sobre el uso de la API de Office 365 que hasta ahora teníamos vigente. Esta versión de API unificada está aún en Preview, por lo que aún pueden haber mejoras o modificaciones, no obstante lo que veremos hoy es la filosofía de la misma.

Antes de entrar de lleno os voy a dejar una recopilación de enlaces que creo que son fundamentales para entender la nueva API Unificada.

http://dev.office.com/unifiedAPIs

https://msdn.microsoft.com/office/office365/HowTo/office-365-unified-api-overview#msg_how_learn_unified_api

https://msdn.microsoft.com/en-us/office/office365/howto/get-started-with-office-365-unified-api

https://msdn.microsoft.com/en-us/office/office365/howto/office-365-unified-api-reference

http://www.vrdmn.com/2015/05/using-office-365-unified-api-in-aspnet.html

¿En qué consiste esta API de Office 365 Unificada?

La nueva API de Office 365 Unificada pretende seguir ofreciendo a los desarrolladores la oportunidad de utilizar los servicios de la suite de productividad de Office 365, pero de forma unificada y a través de una API REST, que nos permite hacer todas las operaciones de una forma mucho más sencilla y alineada con el “standard” de las API de servicios web hoy en día.

Además añaden acceso a nuevos servicios dentro de Office 365, quedando ahora el mapa de entidades de la siguiente forma:

O365_unified_API_entities

Con la API tradicional para usar algunas de las entidades disponibles teníamos siempre que realizar las siguientes acciones:

  • Usar el servicio discovery para encontrar los endpoints
  • Determinar la URL de los servicios a los que la app se quería conectar
  • Obtener y manejar el token de cada servicio y hacer la petición a cada uno de ellos directamente

Desde ahora, por medio de esta nueva API unificada, evitaremos estas operaciones para sustituirlas por una simple API REST. Además no es necesario descubrir y navegar a cada uno de los diferentes endpoints para cada servicio ya que todos comparten uno mismo, con lo que comparten también el sistema de autenticación y autorización. Estos nos permite además fácilmente consumir desde cualquier herramienta o lenguaje de programación esta API.

¿Cómo podemos usar la API?

Vamos a ver ahora algunas de las URLs que tenemos disponible en la API REST unificada para acceder a las distintas entidades de Office 365.

La Url de referencia al servicio la tenemos en la siguiente dirección https://graph.microsoft.com/{version}. A partir de aquí, voy a dejar distintos ejemplo de cómo podemos usar esta referencia para acceder a las distintas entidades.

Acceder a One Drive
https://graph.microsoft.com/{version}/me/files
Accediendo al servicio de Exchange OnLine
https://graph.microsoft.com/{version}/me/Messages
Accediendo a los usuarios de mi tenant
https://graph.microsoft.com/{version}/{myOrganization}/users
Accediendo a los grupos de Office 365
https://graph.microsoft.com/{version}/{myOrganization}/groups
Aplicaciones registradas en Azure AD
https://graph.microsoft.com/{version}/{myOrganization}/applications

Obviamente estas son solo algunas de las URLs principales de los servicios. En el enlace a la referencia de la API podemos ver todas las opciones y todas las oportunidades que tenemos disponibles y os animo a que naveguéis por ahí para ver todo lo que se puede hacer, que como veréis es mucho.

Ejemplo de uso de la nueva API de Office 365 Unificada

Para terminar con el artículo, vamos a ver un ejemplo de código de cómo podemos usar en una aplicación MVC esta nueva API REST.

Para poder usar la API REST unificada de Office 365, tenemos en primer lugar que registrar nuestra App en Azure Active Directory tal y como se comentaba en la entrada que os enlazo a continuación:

Registrando una aplicación en Azure Active Directory

Lo único que tenemos que hacer diferente a cuando íbamos a usar la versión anterior es a la hora de establecer los permisos para la app que estamos registrando. En esta ocasión deberemos añadir los permisos para la nueva API unificada, como se ve en la imagen siguiente, tenemos esta opción disponible.

unifiedAPI

Una vez que ya hemos registrado adecuadamente nuestra app, podemos pasar al código de la aplicación. En la demo que vamos a ver, voy a leer los archivos y directorios de mi One Drive, tal y como hice en el ejemplo con la API anterior. He creado una aplicación MVC y todo el código por simplicidad en el ejemplo, lo he puesto en la misma acción del controlador, aunque si accedéis al último enlace de los que indiqué arriba, podréis ver como se podría organizar el código a través de varias acciones en una aplicación MVC. Vamos a ver el código y luego lo explicaré destacando los puntos más importantes del mismo:

public async Task<ActionResult> Files(string  code)
{
       string authCode = Request.Params["code"];

       // The url in our app that Azure should redirect to after successful signin
       string redirectUri = Url.Action("Files", "Home", null, Request.Url.Scheme);

       var authContext = new AuthenticationContext("https://login.microsoftonline.com/common");

       if(authCode == null)
       {

           // Generate the parameterized URL for Azure signin
           Uri authUri = authContext.GetAuthorizationRequestURL("https://graph.microsoft.com/", ConfigurationManager.AppSettings["ida:ClientID"],
               new Uri(redirectUri), UserIdentifier.AnyUser, null);

           // Redirect the browser to the Azure signin page
           return Redirect(authUri.ToString());
       }

       ClientCredential creds = new ClientCredential(
           ConfigurationManager.AppSettings["ida:ClientID"],
           ConfigurationManager.AppSettings["ida:Password"]);

       // Get the token
       var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
           authCode, new Uri(redirectUri), creds, "https://graph.microsoft.com/");

       // Save the token
       string accesstoken = authResult.AccessToken;

       // Make request
       using (var client = new HttpClient())
       {
           string endpointUri, resourceId;

           using (var request = new HttpRequestMessage(HttpMethod.Get,
             "https://graph.microsoft.com/beta/me/files"))
           {
               request.Headers.Add("Authorization", "Bearer " + accesstoken);

               using (var response = await client.SendAsync(request))
               {
                   List<OneDriveFile> modelList = new List<OneDriveFile>();

                   var content = await response.Content.ReadAsStringAsync();
                   foreach (var item in JObject.Parse(content)["value"])
                   {
                       OneDriveFile newFile = new OneDriveFile
                       {
                          Name = item["name"].ToString(),
                          Size = double.Parse(item["size"].ToString())
                       };

                       modelList.Add(newFile);
                   }

                   ViewBag.files = modelList;

                }
            }
       }

       return View();
}

Vamos a destacar tres aspectos fundamentales de este código:

  • Lo primero que haremos en nuestro código es comprobar si nos hemos autenticado contra Azure Directory, tal y como hacíamos con la API tradicional, y en el caso de que no lo esté nos redirigirá a la página correspondiente para autenticarnos, para todo el proceso de autenticación y autorización se va a usar como hacíamos anteriormente la librería ADAL que tenemos en Nuget. (Líneas 10 a 19)
  • El siguiente paso, es capturar el token de acceso para obtener autorización al hacer las peticiones REST. (Líneas 26 a 30)
  • En el último paso usaremos un cliente Http que nos proporciona C# para hacer llamadas a la API y procesar las respuestas. (Líneas 33 a 62)

Las diferencias con respecto al uso de la versión anterior de la API para Office 365 basada en el servicio discovery la podemos ver con la entrada que publiqué sobre este tema. Nos obstante son obvias, por la facilidad con la que ahora podemos acceder a la API de Office, sin tener que hacer todos los pasos para simplemente acceder al servicio que eran necesarios. Esta es la entrada que os comentaba.

Usando la API de Office 365

Y nada más por hoy, como siempre espero que os resulte interesante, a mi esta nueva versión unificada me ha gustado mucho. Os recomiendo echar un vistazo por todos los enlaces que os he comentado, y ver las oportunidades que nos ofrece esta API, como dije al principio me parecen muy interesantes.

Un saludo a todos.

Autenticación de nuestra Aplicación usando Javascript ADAL

Muy buenas a todos,

En una entrada anterior, vimos como podíamos desarrollar una aplicación web con MVC .NET que nos permitiera acceder a la información guardada en nuestro Office 365. Una parte importante de ese desarrollo era la autenticación contra Azure AD, lo que se hacía por medio del paquete Nugget ADAL (Active Directory Authentication Library).

Hace unos días tuve conocimiento de una librería de Javascript que nos permitía hacer la autenticación contra Azure AD (conocida como Javascript ADAL) y que se podía utilizar en el desarrollo de Single Page Applications de una forma muy sencilla. Así que decidí probarlo para seguir abriendo y conociendo el abanico de oportunidades para trabajar contra Azure AD y luego con la API de Office 365. El primer paso obviamente será el login para después acceder y consultar la API usando CORS.

Así que en la entrada de hoy, os voy a mostrar cómo hacer el login usando esta librería de Javascript. Para el ejemplo he creado un proyecto de MVC vacío en el que he hecho todo el desarrollo. Antes de nada, os dejo, como siempre, los enlaces que me han servido de guía y donde creo que hay información muy valiosa sobre esta librería.

http://www.cloudidentity.com/blog/2015/02/19/introducing-adal-js-v1/

https://github.com/AzureADSamples/SinglePageApp-jQuery-DotNet

Disponemos de una versión de la librería integrada con Angularjs y otra versión que podremos usar con JQuery y otros frameworks que será la versión que voy a usar en mi ejemplo.

Empezando con el ejemplo

Obviamente el primer paso en cualquier caso, es registrar nuestra aplicación en el Azure Active Directory de nuestro Tenant. Tras esto, tenemos que descargar el fichero adal.js.

El siguiente paso que he seguido es crear la vista del ejemplo, que es tal y como veréis a continuación

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="~/Scripts/adal.js"></script>
    <script src="~/Scripts/App/app.js"></script>
</head>
<body>
    <div>
        <h2>Index</h2>

        <a href="javascript:;" class="app-login">Login</a>
        <a href="javascript:;" class="app-logout">Logout</a>
    </div>

</body>
</html>

Esta vista tiene dos botones, uno para hacer login y otro para hacer logout, nada más. El fichero que tiene todo el código es el fichero app.js que podéis ver ahora.

(function () {

    //1.- Initial configuration
    window.config = {
        tenant: '<tentantdomain>',
        clientId: '<clientid>',
        postLogoutRedirectUri: window.location.origin,
        cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
    };
    var authContext = new AuthenticationContext(config);

    //2.- Handle redirect after login
    var isCallback = authContext.isCallback(window.location.hash);
    authContext.handleWindowCallback();

    if (isCallback && !authContext.getLoginError()) {
        window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
    }

    //3.- Check for authenticated information
    var user = authContext.getCachedUser();
    if (user) {
        console.log(user);
    } else {
        console.log("error");
    }

    //4.- Handle events for login & logout
    var $signInButton = $(".app-login");

    $signInButton.click(function () {
        authContext.login();
    });

    var $signOutButton = $(".app-logout");

    $signOutButton.click(function () {
        authContext.logOut();
    });
}());

El código de este ejemplo es una simplificación del ejemplo de Github que os he puesto un poco más arriba y que he usado para entender el proceso que seguía. Lo único que hace este código es mostrar en la consola de depuración los datos del usuario si está logueado o mostrar un texto de error si no lo está. Los puntos más importantes del código son los siguiente:

  1. El primer paso es crear el objeto de configuración, con los datos del tenant y client id que hemos obtenido al registrar la aplicación
  2. A continuación se indica el callback que maneja la redirección después del login
  3. Se comprueba y se muestra la información de logueo del usuario
  4. Por último se crean los eventos que dispararán el login y el logout asociados al click en los enlaces

Y esto es todo, si lo probamos comprobaremos que el resultado es el esperado, cuando no estamos logueados, nos muestra la pantalla de signin de windows para indicar nuestro usuario y contraseña del Azure AD de nuestro tenant.

Lo que os voy a enseñar en próximas entradas es un componente web de Polymer que he creado que utiliza este código para implementar la funcionalidad de signin y signout de una manera muy sencilla y que creo que puede ser de utilidad. Este componente, de hecho ya está en mi GitHub

Un saludo a todos y buen finde.

Usando la API de Office 365

Muy buenas de nuevo a todos,

En la entrada anterior, os contaba como registrar aplicaciones en nuestro Azure AD, y os contaba que lo utilizaría posteriormente para crear aplicaciones web que pudieran acceder a la API de Office 365. Hoy os quiero contar como preparar un proyecto MVC para acceder y usar esta API y mostrar el código que he creado para probarlo todo.

Registrando una aplicación en Azure Active Directory

Actualmente disponemos de muchas opciones cuando nos planteamos extender nuestra plataforma de Office 365, y en función de los requerimientos podremos elegir unas u otras. Si lo que queremos es extender nuestro SharePoint OnLine, podemos optar por desarrollar una SharePoint Hosted o SharePoint Provider App, que nos permitirán manipular la información  de nuestro SharePoint en Office 365 por medio de API REST, JSOM o CSOM. Si en lugar de eso, queremos extender la funcionalidad de nuestro Office 365, y acceder y manipular la información de todo la suite de productividad, entonces podremos usar la API de Office 365, que no solo nos da acceso a SharePoint, sino que nos permite trabajar con Outlook, One Drive, Calendarios, etc.

Esta API de Office 365 y el modelo de aplicaciones de azure registradas en el Azure AD, parece que le va ganando mucho terreno al conjunto tradicional de opciones de desarrollo para SharePoint OnLine. La pregunta ahora es cual de todos ellos tendrá mayor proyección. Recientemente en algún WebCast, he preguntado sobre estos temas a algunos de los MVPs de SharePoint de España, y como conclusión creo que saco en claro que, si bien este último modelo que os comentaba y la API de Office 365 parece que seguirán creciendo y ganando en importancia, las apps para SharePoint y el modelo de objetos de cliente que se está convirtiendo en la herramienta básica de trabajo para los desarrolladores en SharePoint, seguirá teniendo su hueco en este mundo de posibilidades.

Así que toca empezar a ver cómo trabajar con esta API y este es el motivo de esta entrada, una primera toma de contacto con la API de Office 365. Para ello voy a desarrollar un proyecto MVC de ejemplo.

Creando y preparando el proyecto

Previo a empezar con el proyecto, es importante haber registrado en Azure AD una aplicación, para lo que recomiendo leer la entrada que os comentaba al principio del post.

En primer lugar vamos a crear un proyecto web de ASP.NET y seleccionaremos la plantilla MVC. Seleccionamos la plantilla porque ya lleva toda la configuración necesaria de autenticación que, en el caso de hacerlo a partir de un proyecto vacío, tendríamos que configurar a mano.

authentication

Cambiaremos el tipo de autenticación para seleccionar que queremos una autenticación contra Azure AD, y ahí indicaremos los parámetros necesarios.

dataorganizational

En el valor de App ID Url, seleccionaremos el mismo que el que indicamos cuando registramos nuestra aplicación en Azure AD y seleccionaremos la opción de sobreescribir si existe.

Una vez que se ha creado el proyecto, antes de continuar, tenemos que instalar de Nuget la Azure Directory Authentication Library (ADAL).

azure1adal

Y a continuación vamos a project->Add->Connected Services. Ahí nos pedirá registrar nuestra App y a continuación nos mostrará todos los servicios que tenemos disponibles de Office 365. Aquí podremos conceder distintos permisos a nuestra app con respecto a los servicios disponibles.

register permissions

Tras seleccionar los que queremos, vamos a properties y vamos a eliminar de las Urls de retorno la que no va con SSL, esto me ha dado bastante guerra, hasta que descubrí que había que hacerlo, porque tras la autenticación siempre me volvía a la URL con protocolo http y me daba error.

properties

Tras todos estos pasos, ya tenemos todo nuestro proyecto configurado para poder usar la API de Office 365 para los servicios que le hemos concedido permisos. Además si lo hemos hecho todo bien, veremos que si vamos a nuestro Azure AD, al apartado de aplicaciones y a su configuración, se ha configurado correctamente, y se han concedido los permisos necesarios y creado las claves correspondientes, además de que todo esto se habrá reflejado correctamente en nuestro web.config

Ahora llega el momento del código.

El código para acceder a la API de SharePoint

En mi caso, he metido todo el código dentro del método de la acción Index del controlador, al tratarse de un código de ejemplo, no he querido complicarlo mucho creando una clase de servicio y demás aspectos de “mejores prácticas”, que se pueden o se deben hacer. Eso lo dejo para más adelante ;).

En el caso del ejemplo, lo que voy a hacer es mostrar en una lista, toda la información de los archivos que tengo en mi One Drive, ordenados de mayor a menor tamaño.

El código para trabajar con la API, puede resultar enrevesado y un poco engorroso al principio, pero al final, una vez que trabajas con él, te das cuenta que una parte importante, se repite siempre para todos los servicios y es común a todos, y que solo hay que cambiar la parte correspondiente a cada servicio concreto. Os pongo el código completo y os voy contando las partes más importantes.

public async Task<ActionResult> Index(string code)
{
     try
     {
          DiscoveryClient disco = Helpers.GetFromCache("DiscoveryClient&quot;) as DiscoveryClient;
          SharePointClient sharepointClient = Helpers.GetFromCache("SharePointClient") as SharePointClient;
          CapabilityDiscoveryResult filesDisco = Helpers.GetFromCache("CapabilityDiscoveryResult") as CapabilityDiscoveryResult;
          string authorized = Helpers.GetFromCache("authorized") as string;

          AuthenticationContext authContext = new AuthenticationContext(
             ConfigurationManager.AppSettings["ida:AuthorizationUri"] + "/common",
                   true);

          ClientCredential creds = new ClientCredential(
              ConfigurationManager.AppSettings["ida:ClientID"],
              ConfigurationManager.AppSettings["ida:Password"]);

          //1.- Looking for authentication code to get the discovery service
          if (code == null && disco == null)
          {
              Uri redirectUri = authContext.GetAuthorizationRequestURL(
                  discoResource,
                  creds.ClientId,
                  new Uri(Request.Url.AbsoluteUri.Split('?')[0]),
                  UserIdentifier.AnyUser,
                  string.Empty);

              return Redirect(redirectUri.ToString());
          }

          //2.- Getting the discovery client
          if (code != null && disco == null)
          {
              disco = new DiscoveryClient(new Uri(discoEndpoint), async () =>
              {

                  var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                      code,
                      new Uri(Request.Url.AbsoluteUri.Split('?')[0]),
                      creds);

                  return authResult.AccessToken;
              });

              Helpers.SaveInCache("DiscoveryClient", disco);
          }

          //3.- Getting the capabilites to access to one drive files
          if (filesDisco == null)
          {
              filesDisco = await disco.DiscoverCapabilityAsync("MyFiles");
              Helpers.SaveInCache("CapabilityDiscoveryResult", filesDisco);
          }

          //4.- Looking for authentication to get sharepoint service
          if (filesDisco != null && authorized == null)
          {
              Helpers.SaveInCache("authorized", "");

              Uri redirectUri = authContext.GetAuthorizationRequestURL(
                  filesDisco.ServiceResourceId,
                  creds.ClientId,
                  new Uri(Request.Url.AbsoluteUri.Split('?')[0]),
                  UserIdentifier.AnyUser,
                  string.Empty);

              return Redirect(redirectUri.ToString());
          }

          //5.- Getting sharePoint Client
          if (sharepointClient == null)
          {
              sharepointClient = new SharePointClient(filesDisco.ServiceEndpointUri, async () =>
              {
                  var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                      code,
                      new Uri(Request.Url.AbsoluteUri.Split('?')[0]),
                      creds);

                  return authResult.AccessToken;
              });

              Helpers.SaveInCache("SharePointClient", sharepointClient);
          }

          //6.- Reading files from sharepointClient
          var onedrivefiles = await sharepointClient.Files.ExecuteAsync();

          var filesOrdered = from files in onedrivefiles.CurrentPage
                             orderby files.Size descending
                             select files;

          List<OneDriveFile> modelList = new List<OneDriveFile>();

          //7.- Adding model list from files got from service
          foreach (var file in filesOrdered)
          {
              modelList.Add(new OneDriveFile
              {
                  Name = file.Name,
                  Size = file.Size,
                  Created = file.DateTimeCreated
              });
          }

          ViewBag.files = modelList;

          return View();
      }
      catch (Exception ex)
      {
          return View("Error");
      }
}
  1. Lo primero que haremos será es solicitar el token de autenticación en el caso de que no exista para poder acceder al servicio discovery
  2. El segundo paso, es obtener un discoveryClient a partir del token obtenido previamente y que nos servirá para solicitar las capacidades que necesitemos de la API de Office 365
  3. Tras esto, se solicitan las capacidades al servicio de discovery que habíamos cargado previamente.
  4. El siguiente paso, es solicitar el token de autenticación para el servicio correspondiente a la capacidad solicitada, si no está disponible. Hasta este punto, para todas las APIs de Office 365 es común, la única diferencia, es la capacidad que requeriremos en cada ocasión, lo que lo hace un buen candidato para encapsular correctamente, por eso decía antes que aunque pueden resultar engorrosos todos los pasos, el funcionamiento luego es muy repetitivo. En este caso, hemos solicitado la capacidad “MyFiles” para obtener la información de OneDrive.
  5. A continuación obtenemos un SharePointClient, para acceder ya al servicio de OneDrive
  6. En este momento, leemos los archivos y usando LinQ los ordenamos por tamaño
  7. Y ya para terminar los metemos en una lista del modelo de datos que hemos definido para mostrarlo en la vista posteriormente

Para el ejemplo he creado un modelo llamado OneDriveFile que os pongo también a continuación

public class OneDriveFile
{
    public string Name{ get; set;}
    public double Size{ get; set;}
    public DateTimeOffset Created {get; set;}
}

El resultado

Si ejecutamos el código, o lo depuramos, veremos, tras solicitar la autenticación contra el Azure AD, que nos muestra los archivos que tengo en mi One Drive de Office 365, y ordenados de mayor a menos tamaño

resultado

En mi caso la mayoría, de algunos eventos de desarrollo a los que he asistido y de los que aprendo casi todo :).

Antes de terminar, os dejo referencia de la información que me ha servido a mí para poder llevar a cabo este código, y que ha partido de un evento al que asistí con la gente de MadPoint, donde hicieron un ejemplo incluso más extenso que este sobre el uso de la API de Office 365. Yo básicamente he partido de ese código, y lo que he aprendido ha sido a hacer todas las configuraciones necesarias para que funcione, y modificar el mismo para que se ajuste exactamente al tipo de ejemplo que quería hacer, que si que se diferencia un poco del que se hizo en el evento. No obstante gracias por todo lo que aprendí allí. Os dejo los enlaces.

http://www.sinsharepointnohayparaiso.com/recursos-y-documentos

https://github.com/MadPoint/Eventos/tree/master/2015.02%20Prepara%20tus%20apps%20de%20SharePoint%20y%20Office%20365%20para%20el%20futuro

Y nada más por ahora, espero que os sirva este ejemplo, yo hasta que he configurado bien todos los aspectos, el registro de la app, los permisos, las URLs de retorno y todo lo necesario, he pasado algún tiempo entretenido.

Un saludo y hasta la próxima.