Cómo hacer uso del tenant de WAAD de Office 365 junto con ACS
- Cómo securizar aplicaciones web usando ACS y tokens JWT.
- Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF.
- Cómo securizar servicios WebAPI usando ACS y tokens JWT.
- Cómo securizar una aplicación MVC que contenga tanto aplicaciones web como servicios WebAPI.
- Cómo securizar aplicaciones web usando Windows Azure Active Directory ( WAAD ).
- Cómo hacer uso del tenant de WAAD de Office 365 para securizar aplicaciones web con ACS.
Como ya comentaba en el post anterior, Office 365 hace uso de Windows Azure Active Directory para la autenticación, por lo que si posees ya una cuenta de Office 365 ya dispones de un tenant de WAAD para securizar tus aplicaciones.
Si por ejemplo estás autenticado en tu subscripción de Office 365 y vas a http://activedirectory.windowsazure.com podrás ver la información y configuración de tu tenant de WAAD, pero…¿Se puede ver dentro del portal de Windows Azure como veíamos en el post anterior?
Sí, se puede ver dentro del portal de Windows Azure, de dos maneras:
- Creando una subscripción de Windows Azure asociada al administrador de la subscripción de Windows Azure.
- Llamando a centro de soporte para que asocien una subscripción que ya tenga con el usuario administrador de Office 365.
Una vez hecho uno de estos pasos, si estas autenticado en Office 365 con el usuario administrador y vamos al portal de Windows Azure, podremos ver el tenant de WAAD tal y como veíamos en el post anterior.
Sea como sea, en este post vamos a ver cómo podemos usar el tenant de WAAD de Office 365 como un proveedor de identidad de ACS, para lo cuál no necesitamos que el tenant se vea en el portal de Windows Azure.
¿Qué conseguimos con esto?
Si configuramos este proveedor de identidad, podríamos securizar una aplicación web o WebAPI, tal y como ya hemos visto,desplegarlas en Windows Azure y usar los usuarios de Office 365 para autenticarse en todas las aplicaciones,con Single Sign On entre ellas claro.
Si además nos encontramos en un escenario real corporativo, seguramente tendremos el Office 365 sincronizado con nuestro dominio corporativo, por lo que es una manera de usar nuestras credenciales corporativas para logearnos en cualquier aplicación, ya esté en Office 365 o desplegada directamente en Windows Azure.
Desde el portal de Windows Azure, desde el namespace de ACS que hemos estado usando en el resto de ejemplo, añadiremos un nuevo proveedor de identidad de tipo “WS-Federation”.
E indicaremos la URL dónde están los metadatos:
Así mismo, podremos configurar las diferentes aplicaciones para que usen los proveedores de identidad que queramos. Hasta ahora habíamos usado siempre Windows Live ID.
Por último, tenemos que configurar el tenant de Office 365 para que permite conexiones del ACS para la autenticación.
Para poder hacer esta configuración no tenemos interfaz de usuario y necesitamos hacer uso las “Windows Azure Active Directory Module for Windows Powershell” para poder lanzar estos comandos y realizar la configuración:
connect-msolservice import-module msonlineextended –force $replyUrl = New-MsolServicePrincipalAddresses -Address "https://[yournamespace].accesscontrol.windows.net/" New-MsolServicePrincipal -ServicePrincipalNames @("https://[yournamespace].accesscontrol.windows.net/") -DisplayName "[displayName]" -Addresses $replyUrl
Y con estos pasos, ya podremos usar las credenciales que estuviéramos usando en Office 365 para autenticarnos.
Securizar aplicaciones web usando Windows Azure Active Directory
- Cómo securizar aplicaciones web usando ACS y tokens JWT.
- Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF.
- Cómo securizar servicios WebAPI usando ACS y tokens JWT.
- Cómo securizar una aplicación MVC que contenga tanto aplicaciones web como servicios WebAPI.
- Cómo securizar aplicaciones web usando Windows Azure Active Directory ( WAAD ).
- Cómo hacer uso del tenant de WAAD de Office 365 para securizar aplicaciones web con ACS.
Hasta ahora hemos visto varios ejemplos de securización de aplicaciones dónde siempre hemos hecho uso de Windows Azure Access Control. En este post hablaremos de Windows Azure Active Directory el cuál puede usarse de forma independiente a ACS o como un proveedor de identidad más de ACS.
Como en los ejemplos anteriores, partiremos de una aplicación ASP.NET MVC 4, en la cuál queremos incluir un mecanismo de seguridad basado en WAAD.
Para ello, lo primero, necesitaremos crear a través del portal de Windows Azure un tenant de WAAD. Tened en cuenta que los tenant van asociados a los usuarios, no a la subscripción, y sólo se permite uno por usuario. Además, a día de hoy no se puede borrar una vez creado…
Comentar que Office 365 usa WAAD, por lo que si ya tenéis una cuenta de Office 365 ya tenéis un tenant de WAAD que podrías usar, tal y como veremos en el siguiente post.
Desde este menú podremos crear nuestro tenant, indicando los datos del mismo.
Una vez creado, podremos crear usuarios,usuarios que son los que usaremos para autenticarnos en la aplicación.
Y si lo preferimos,podemos sincronizar el tenant que acabamos de crear con un Active Directory que tengamos on-premise y así usar los mismos usuarios que tengamos ya creados.
Una vez que tenemos los usuarios, podemos dar de alta las aplicaciones que queremos securizar.
e indicar el identificar único de la aplicación, como la URL dónde está desplegado. Si estamos probando en local la URL será algo como http://localhost:29350/
Una vez hecho estos pasos iremos a la aplicación web y volveremos a hacer uso de la herramienta que nos permite configurar la seguridad basada en WIF.
En este caso, indicaremos que queremos usar Windows Azure Active Directory, indicando el identificador único de la aplicación que hemos puesto anteriormente, así cómo la URL a los metadatos del STS. Esta URL se obtiene desde el portal de Windows Azure, dentro de la aplicación que hemos creado.
Y una vez hecho estos pasos, si ejecutamos la aplicación (F5) veremos cómo se nos redirige a la página de login dónde deberemos introducir las credenciales del un usuario de WAAD o de nuestro dominio si es que lo tuviéramos sincronizado.
Cómo securizar una aplicación que contenga tanto aplicaciones web como servicios WebAPI
- Cómo securizar aplicaciones web usando ACS y tokens JWT.
- Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF.
- Cómo securizar servicios WebAPI usando ACS y tokens JWT.
- Cómo securizar una aplicación MVC que contenga tanto aplicaciones web como servicios WebAPI.
- Cómo securizar aplicaciones web usando Windows Azure Active Directory ( WAAD ).
- Cómo hacer uso del tenant de WAAD de Office 365 para securizar aplicaciones web
En los ejemplos anteriores hemos visto cómo securizar una aplicación ASP.NET MVC y una aplicación WebAPI haciendo uso de ACS y tokens JWT.
¿Pero qué pasa si en el mismo proyecto tenemos las dos cosas? Una aplicación web a la cuál un usuario puede acceder a través del navegador y un servicio WebAPI que se usa tanto desde el javascript de la aplicación web, como desde otros clientes como pueden ser una aplicación Windows 8 o Windows Phone.
En este caso, tendremos que hacer los pasos vistos en los dos post anteriores, pero veremos cómo una vez juntos no van a funcionar las llamadas al servicio WebAPI, salvo las propias que podamos hacer desde el javascript de la aplicación.
Cuando hacemos uso de WIF para autenticar la aplicación web, TODAS las llamadas que se realizar deben estar autenticadas. En caso de no estar autenticadas, se nos redirige a la pantalla de login para que podamos introducir las credenciales.
Si las llamadas las intentamos realizar por código, por ejemplo desde una aplicación Windows 8 haciendo uso de httpClient, estas llamadas serán igualmente redirigidas a la pantalla de login, aunque mandemos en las cabeceras el token de seguridad.
Solución? En mi caso lo he solucionado de la siguiente manera:
Lo primero es añadir la posibilidad de llamar a los servicios WebAPI a través de dos rutas diferentes. Una de las rutas será usada por la aplicación web, cuando desde el código JavaScript quiera llamar a estos servicios, mientras la otra ruta será usada para el resto de clientes; Windows 8,Windows Phone…
config.Routes.MapHttpRoute(
name: "DefaultApi",routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiJs",
routeTemplate: "apijs/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
En el fichero de configuración establezco que la ruta que va a ser usada por las “aplicaciones externas” permita llamadas anónimas.
<location path="api"> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </location>
y por último, en el DelegationHandler haré que sólo se valide el token si la llamada no es autenticada.
if (Thread.CurrentPrincipal.Identity.IsAuthenticated) { return base.SendAsync(request, cancellationToken); }
De esta manera conseguimos:
Si un usuario accede a través del navegador se le pedirán las credenciales para poder entrar en la web. Una vez autenticado, todas las llamadas que se hagan desde el JavaScript ya estarán autenticadas, por lo que no es necesario que el DelegationHandler haga nada.
Cuando hacemos por código desde una aplicación externa, haremos uso de la ruta que permite llamada anónimas y así evitar que se nos mande a la página de login. En este caso, el DelagationHandler sí tendrá que validar el token de seguridad y establecer la identidad en la llamada.
Cómo securizar servicios WebAPI usando ACS y tokens JWT
- Cómo securizar aplicaciones web usando ACS y tokens JWT.
- Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF.
- Cómo securizar servicios WebAPI usando ACS y tokens JWT.
- Cómo securizar una aplicación MVC que contenga tanto aplicaciones web como servicios WebAPI.
- Cómo securizar aplicaciones web usando Windows Azure Active Directory ( WAAD ).
- Cómo hacer uso del tenant de WAAD de Office 365 para securizar aplicaciones web
En el primer post de la serie veíamos cómo es posible securizar una aplicación web ASP.NET MVC como ACS y token JWT. En este post haremos un ejemplo similar, pero securizando un servicio ASP.NET WebAPI al cuál queremos llamar desde un cliente de forma segura.
Una vez creada, veremos cómo ésta aplicación tiene unos controladores de ejemplo que podemos usar para el ejemplo que estamos mostrando, ya que lo que nos importante en este caso es cómo securizar el acceso.
Con el proyecto de ejemplo, si ejecutamos la aplicación con F5 podemos acceder a los controladores WebAPI a través del protocolo GET desde el propio navegador y ver los resultados que devuelve. Al no tener seguridad cualquiera puede consultarlos.
Una vez que tenemos la aplicación de ejemplo, como en caso anterior, será necesario crear un namespace de ACS así como una relaying party con las URLs dónde estamos desplegando el servicio WebAPI en local.
Para seguir con el ejempo, el siguiente paso será añadir una referencia a System.IdentityModel, así como instalar a través de Nuget “JSON Web Token Handler For the Microsoft .Net Framework 4.5”, paquete que va a proporcionarnos diferentes clases para el manejo de tokens JWT.
Una vez realizado estos pasos, la principal diferencia con el ejemplo de MVC es que aquí no podremos hacer uso de la herramienta “Identity and Access…” que veíamos en el post anterior y la cuál nos permitía configurar nuestra aplicación para hacer uso de ACS.
En este caso tendremos que desarrollar nuestro propio DelegatingHandler para que poder validar en todas las peticiones que se realicen al servicio WebAPI que el cliente está debidamente autenticado contra el proveedor de identidad y STS que tengamos configurado en nuestro ACS.
A través del Global.asax añadiremos nuestro validador personalizado, el cuál se encarga de asegurarse de que el token se envían en las cabeceras de todas las peticiones, que el token es correcto y es establecer la identidad para que desde los controladores WebAPI pueda acceder a toda la información del usuario autenticado, por ejemplo, los claims.
GlobalConfiguration.Configuration.MessageHandlers.Add(new TokenValidationHandler());
El código de nuestro handler sería el siguiente:
internal class TokenValidationHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpStatusCode statusCode; string token; if (!TryRetrieveToken(request, out token)) { statusCode = HttpStatusCode.Unauthorized; return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode)); } try { // Use JWTSecurityTokenHandler to validate the JWT token JWTSecurityTokenHandler tokenHandler = new JWTSecurityTokenHandler(); List<string> issuers = new List<string>(); issuers.AddRange(ConfigurationManager.AppSettings["Issuers"].Split(new[] { '','' })); // Set the expected properties of the JWT token in the TokenValidationParameters TokenValidationParameters validationParameters = new TokenValidationParameters() { AllowedAudience = ConfigurationManager.AppSettings["AllowedAudience"], ValidIssuers = issuers, // Fetch the signing token from the FederationMetadata document of the tenant. SigningToken = new X509SecurityToken(new X509Certificate2(GetSigningCertificate(ConfigurationManager.AppSettings["ida:FederationMetadataLocation"]))) }; Thread.CurrentPrincipal = tokenHandler.ValidateToken(token, validationParameters); HttpContext.Current.User = Thread.CurrentPrincipal; return base.SendAsync(request, cancellationToken); } catch (SecurityTokenValidationException) { statusCode = HttpStatusCode.Unauthorized; } catch (Exception) { statusCode = HttpStatusCode.InternalServerError; } return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode)); } // This function retrieves ACS token (in format of OAuth 2.0 Bearer Token type) from // the Authorization header in the incoming HTTP request from the ShipperClient. private static bool TryRetrieveToken(HttpRequestMessage request, out string token) { token = null; IEnumerable<string> authzHeaders; if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.COUNT() as Computed > 1) { // Fail if no Authorization header or more than one Authorization headers // are found in the HTTP request return false; } // Remove the bearer token scheme prefix and return the rest as ACS token var bearerToken = authzHeaders.ElementAt(0); token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken; token = bearerToken.StartsWith("Authorization Bearer ") ? bearerToken.Substring(21) : bearerToken; return true; } public static byte[] GetSigningCertificate(string metadataAddress) { if (metadataAddress == null) { throw new ArgumentNullException(metadataAddress); } using (XmlReader metadataReader = XmlReader.Create(metadataAddress)) { MetadataSerializer serializer = new MetadataSerializer() { CertificateValidationMode = X509CertificateValidationMode.None }; EntityDescriptor metadata = serializer.ReadMetadata(metadataReader) as EntityDescriptor; if (metadata != null) { SecurityTokenServiceDescriptor stsd = metadata.RoleDescriptors.OfType<SecurityTokenServiceDescriptor>().First(); if (stsd != null) { X509RawDataKeyIdentifierClause clause = stsd.Keys.First().KeyInfo.OfType<X509RawDataKeyIdentifierClause>().First(); if (clause != null) { return clause.GetX509RawData(); } throw new Exception("The SecurityTokenServiceDescriptor in the metadata does not contain the Signing Certificate in the <X509Certificate> element"); } throw new Exception("The Federation Metadata document does not contain a SecurityTokenServiceDescriptor"); } throw new Exception("Invalid Federation Metadata document"); } } }
Si una vez realizado estos cambios, volvemos a ejecutar la aplicación y realizamos una llamada desde el navegador, veremos cómo todas las llamadas pasan por nuestro validador personalizado, el cuál rechazará todas las llamadas que no contenga un token de seguridad validado.
El último paso del ejemplo será realizar un cliente C# que sea capaz de llamar al servicio WebAPI pasando un token de seguridad válido para nuestro STS.
En este caso he creado un proyecto de Test, al que he añadid el paquete “Windows Azure Authentication Library”, el cuál simplifica enormemente el trabajo con WIF, ya sea con ACS o con Windows Azure Active Directory.
El siguiente código muestra cómo es posible realizar una llamada al servicio WebAPI.
En el ejemplo se hace uso de la clase AuthenticationContext disponible en WAAL, en la cuál indicamos el namespace de ACS con el que estemos trabajando, así como el nombre de la relaying party para el cuál queremos obtener un token de seguridad.
El método AcquireToken nos mostraré una interfaz de usuario en función del proveedor o proveedores configurados en ACS, para que podamos autenticarnos.
Una vez autenticados, podremos generar un token para poder mandarlo en las cabeceras de autenticación. En este caso, el delegationHandler que hemos desarrollado anteriormente validará correctamente el token y establecerá la identidad en la llamada.
[TestClass]
public class DemoWebAPITests
{
[TestMethod]
[TestCategory("Integration")]
public async Task TestWebAPIService()
{
var authContext = new AuthenticationContext("https://estoyenlanube.accesscontrol.windows.net");
AssertionCredential credential = authContext.AcquireToken("http://localhost:29350/");
var token = credential.CreateAuthorizationHeader();
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", token);
var response = await httpClient.GetStringAsync("http://localhost:29350/api/values");
}
}
Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF
Siguiente con la serie de posts dedicada a la securización de aplicaciones, este post veremos cómo desplegar en Windows Azure Web Sites la aplicación web desarrollada en el post anterior y un par de puntos que tendremos que tener en cuenta para que todo funcione sin problemas.
- Cómo securizar aplicaciones web usando ACS y tokens JWT.
- Desplegar aplicaciones web en Windows Azure WebSites que hagan uso de WIF.
- Cómo securizar servicios WebAPI usando ACS y tokens KWT.
- Cómo securizar una aplicación MVC que contenga tanto aplicaciones web como servicios WebAPI.
- Cómo securizar aplicaciones web usando Windows Azure Active Directory ( WAAD ).
- Cómo hacer uso del tenant de WAAD de Office 365 para securizar aplicaciones web
El primer paso es crear un nuevo Web Site desde el portal de WIndows Azure dónde desplegaremos la aplicación ASP.NET desarrollada en el post anterior y que hace uso de ACS y tokens JWT.
Una vez creado el site, modificaremos en namespace de ACS para que en lugar de hacer uso las URL locales, haga uso de las URL de WIndows Azure dónde desplegaremos la aplicación.
En este caso estamos modificando la misma relaying party que teníamos ya, pero en un escenario real os recomendaría tener dos “relaying party”, una configurada para funcionar en local y otra para funcionar cuando esté desplegada en Windows Azure y hacer uso de las transformaciones que soporta web.config para que cuando ésta se despliega en Windows Azure la configuración sea modificada para tener la configuración adecuada.
El siguiente paso, será utilizar el wizard de publicación que nos proporciona el Sdk de Windows Azure para publicar de manera directamente desde Visual Studio.
Este wizard de forma sencilla nos permite indicar las credenciales de nuestra subscripción Windows Azure, así como indicar el servicio sobre el que se quiere desplegar la aplicación, tal y como se ve en las imágenes siguientes:
Y una vez desplegada, si lo hacemos con los errores remotos activados ( <customErrors mode="Off"></customErrors> ) veremos el siguiente error!!
The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread”s user context, which may be the case when the thread is impersonating.
Este error se produce por el uso DAPI, método por defecto para proteger las cookies en aplicaciones WIF y el cuál no está disponible en Windows Azure Web Sites.
Cambiarlo es sencillo, ya que la propia herramienta nos permite indicar que queremos usar un método alternativo, chequeando la opción “Enable Web farm ready cookies” en el pestaña de configuración del asistente “Identity and Access…”.
Sino podemos cambiar manualmente estas entradas en el fichero de configuración:
<securityTokenHandlers> <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />




