- 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.
- Securizar aplicaciones Windows 8 con ACS y WAAD
Después de unos cuántos post sobre gestión de identidad y seguridad basada en claims, en esta nueva entrada toca hablar sobre cómo securizar aplicaciones Windows 8, escenario que es algo distinto a los que hemos visto hasta ahora.
En muchos casos, cuando realizamos aplicaciones Windows 8 éstas necesitan hacer uso de servicios de backend, WebAPI por ejemplo, los cuáles pueden estar securizados empleado Windows Azure Active Directory (WAAD) o Windows Azure Access Control, tal y como hemos visto en los post anteriores. Cualquiera de las dos opciones pueden ser válidas para el caso dónde nos encontramos.
En cualquiera de los dos escenarios, la aplicación Windows 8 tendrá que pedir al usuario que se autentique contra el proveedor de identidad configurado para que una vez autenticado la aplicación pueda hacer llamadas a los servicios de backend.
En el post sobre cómo securizar un servicio WebAPI veíamos cómo incluir la seguridad en el servicio y cómo poder hacer un cliente C# que llame a este servicio, pidiendo al usuario las credenciales de autenticación. En ese ejemplo hacíamos uso de Windows Azure Authentication Library para simplicar la seguridad. El código era este:
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");
Si intentamos hacer lo mismo en una aplicación Windows 8, veremos cómo también está disponible la librería Windows Azure Authentication Library, pero con una gran diferencia, que ésta sólo funciona si el servicio WebAPI está securizado usando Windows Azure Active Directory, si usamos ACS, este código NO funcionará!
Entonces, si usamos Windows 8 y WAAD el código será prácticamente igual, salvo que el método AcquireToken nos pedirá un ClientID que podemos encontrar dentro del portal de Windows Azure.
y entonces….Qué pasa si usamos ACS para la securización? Pues que el tema se complica un poco; Tendremos que hacer uso del WebAuthenticationBroker y hacer alguna pequeña modificación en nuestro servicio WebAPI.
A modo de resumen, el proceso de autenticación que implementaremos será el siguiente:
- La aplicación Windows 8 usará WebAuthenticationBroker, pidiendo a ACS que autentique el usuario.
- El usuario tiene que introducir las credenciales para el proveedor de identidad configurado.
- Una vez que el ACS autentica al usuario, éste le debe redirigir a un controlador del servicio WebAPI.
- El servicio WebAPI generará un token de autenticación, que devolverá a a la aplicación Windows 8.
- La aplicación Windows 8 podrá usar este token para hacer las llamadas al servicio WebAPI.
Ahora el código…
En la aplicación Windows 8 el código sería similar al siguiente:
WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync( WebAuthenticationOptions.None, new Uri("https://estoyenlanube.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=https://estoyenlanube.azurewebsites.net/&wreply=https://estoyenlanube.azurewebsites.net/api/federation"), new Uri("https://estoyenlanube.azurewebsites.net/api/federation/end")); if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success) {
En este ejemplo, el namespace del ACS es “estoyenlanube”, mientras que el servicio WebAPI lo tengo desplegado en https://estoyenlanube.azurewebsites.net. Lo tengo desplegamos en un servidor real porque ACS no es capaz de redirigir a direcciones localhost.
https://estoyenlanube.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=https://estoyenlanube.azurewebsites.net/&wreply=https://estoyenlanube.azurewebsites.net/api/federation
Con esta URL le estamos pidiendo al WebAuhenticationBroker que autentique usando el namespace estoyenlanube y el relaying party https://estoyenlanube.azurewebsites.net, Así mismo, le decimos que una vez autentique al usuario redirija la petición a un controlar del servicio WebAPI, el cuál generará el token.
El servicio WebAPI recibirá la petición y generará el token para que el cliente Windows 8 lo obtenga:
public class FederationController : ApiController { [HttpPost] public HttpResponseMessage Post() { var response = this.Request.CreateResponse(HttpStatusCode.Redirect); response.Headers.Add("Location", "/api/federation/end?token=" + ExtractBootstrapToken()); return response; } protected virtual string ExtractBootstrapToken() { var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext; JWTSecurityToken jwt = bootstrapContext.SecurityToken as JWTSecurityToken; return jwt.RawData; } }
En el fichero de configuración del servicio WebAPI también es necesario cambiar la configuración para que el controlador pueda generar el token:
<identityConfiguration saveBootstrapContext="true">
Finalmente, el cliente Windows 8, si la autenticación es correcta, podrá obtener el valor del parámetro token y usarlo para realizar las llamadas correspondientes al servidor:
var token = webAuthenticationResult.ResponseData.Substring(webAuthenticationResult.ResponseData.IndexOf("token=", StringComparison.Ordinal) + 6);
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "Bearer " + token);
var response = await httpClient.GetStringAsync("http://localhost:29350/api/values");
Y ya tenemos todo el proceso 🙂