Sécuriser un service WCF exposé sur le Service Bus d’Azure
On a vu dans un post précédent comment profiter de la fonctionnalité de Relying Messaging du Service Bus d’Azure pour exposer nos services WCF (SOAP ou OData) internes sur internet :
http://sebastienollivier.fr/blog/azure/relying-messaging-service-bus-azure/
Les services ont été configurés sans sécurité, c’est à dire que n’importe qui pourra accéder et interroger nos services. Pour sécuriser des services, le Service Bus d’Azure prévoit d’utiliser ACS (Access Control Service).
On va voir dans ce post comment sécuriser des services exposés sur le Service Bus et ensuite comment interroger ces services.
Exposer un service WCF via le Service Bus Azure
Le Service Bus apporte les fonctionnalités de messagerie et de connectivité sécurisées à Azure.
La partie Relying Messaging du Service Bus permet d’exposer des services hébergés On-Premise sur Azure, de manière totalement sécurisée, sans avoir à créer de DMZ. Le Relying Messaging prend en charge l’ensemble des protocoles de services Web.
On va voir à travers ce post comment exposer un service WCF SOAP ainsi qu’un service WCF Data Services au travers du Service Bus d’Azure.
Microsoft met à disposition la dll Microsoft.ServiceBus.dll pour interagir avec le Service Bus. Cette dll définit un ensemble d’éléments (binding, behavior, etc.) qui nous permettront de configurer les services WCF.
Tout va se passer dans les fichiers de configuration des services.
Configurer un service WCF SOAP
La première configuration à effectuer est l’ajout des trois extensions suivantes, définies dans la dll Microsoft.IdentityModel.dll :
- TransportClientEndpointBehavior : Permet de renseigner les credentials à utiliser pour se connecter au Service Bus
- ServiceRegistrySettings : Permet de définir la visibilité du service WCF sur le Service Bus. Si la visibilité est définie sur Public, le service sera visible en naviguant vers l’URL du Service Bus.
- WS2007HttpRelayBinding : Représente un binding de type WS2007HttpBinding supportant une liaison avec le Service Bus.
<extensions>
<behaviorExtensions>
<add name="transportClientEndpointBehavior"
type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement,
Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
<add name="serviceRegistrySettings"
type="Microsoft.ServiceBus.Configuration.ServiceRegistrySettingsElement,
Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</behaviorExtensions>
<bindingExtensions>
<add name="ws2007HttpRelayBinding"
type="Microsoft.ServiceBus.Configuration.WS2007HttpRelayBindingCollectionElement,
Microsoft.ServiceBus, Version=1.6.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</bindingExtensions>
</extensions>
On va ensuite ajouter un nouvel Endpoint Behavior:
<endpointBehaviors>
<behavior name="sharedSecretClientCredentials">
<serviceRegistrySettings discoveryMode="Public">
</serviceRegistrySettings>
<transportClientEndpointBehavior>
<tokenProvider>
<sharedSecret issuerName="owner"
issuerSecret="**********" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>
Ce behavior permet à la fois de déclarer la visibilité du service (via serviceRegistrySettings) et les credentials à utiliser pour se connecter sur le Service Bus (via transportClientEndpointBehavior).
ADFS 2 vs ACS
Hormis le fait que ADFS 2 et ACS soient respectivement des STS (Security Token Service) version On-Premise et version Cloud de Microsoft, ces deux services proposent des fonctionnalités légèrement différentes.
ADFS 2 :
- Mapping de claims évolué grâce au Custom Attribut Store (possibilité de récupérer des claims depuis un provider custom, ex: base de données, service web, etc.)
- Permet d’exposer un Active Directory en tant que Identity Provider
- Customisation possible du site de fédération passive pour intégrer de la sécurisation forte (ex: Captcha, Gemalto, etc.) ou d’autres fonctionnalités avancées
Azure ACS :
- Intégration facilitée des providers de type réseaux sociaux
- En fédération passive, le token SAML peut être renvoyé soit par redirection HTTP, soit par JavaScript Notify au format JSON (méthode JavaScript permettant de notifier le conteneur de la page). ADFS 2 ne propose que l’envoi par redirection HTTP.
- Exposition d’un fichier JavaScript permettant de récupérer la liste des fournisseurs d’identité au format JSON
- Hébergement et personnalisation de la page de sélection du fournisseur d’identité
- Possibilité de restreindre les fournisseurs d’identité par application
- Support des tokens SWT
De manière à profiter des fonctionnalités des deux services, il est possible de les combiner :
- Utiliser ACS comme IDP de ADFS 2 : Permet par exemple d’exposer les providers de type réseaux sociaux au travers de ADFS (via ACS)
- Utiliser ADFS 2 comme IDP de ACS : Permet par exemple de renvoyer un token SAML créé par ADFS via JavaScript Notify
A bientôt.
Récupérer les informations de l’utilisateur authentifié depuis ACS via Live ID
Lorsqu’on utilise Live ID comme Identity Provider sur ACS, le seul Claim renvoyé par Live ID est un hash de l’UID du compte Live utilisé. Les informations telles que l’adresse email, le nom ou le prénom ne sont pas renvoyées.
Pour retrouver ces informations, la plupart des sites internet utilisant Live ID propose un formulaire d’enregistrement où l’utilisateur authentifié pourra renseigner ses informations (au moins son email). Au delà du fait qu’on oblige l’utilisateur à renseigner des informations qu’il a déjà renseignées à la création de son compte Live, cette solution n’est pas fiable puisqu’on ne peut pas vérifier que l’email renseigné correspond à l’email avec lequel l’utilisateur s’est logué, à moins d’envoyer un email à cette adresse contenant une URL de validation d’inscription… mais là le processus d’inscription devient infernal pour l’utilisateur.
Le SDK Live permet d’accéder aux informations du compte Live ID de l’utilisateur logué, en utilisant le même principe de consentement que Facebook et GMail.
Le principe est simple. Notre application va être enregistrée auprès de Live ID. Lorsqu’on va demander les informations utilisateur, le SDK Live va vérifier les droits de notre application sur le compte Live ID. Si aucun droit n’existe, le SDK va demander à l’utilisateur s’il accepte d’autoriser l’accès aux informations de son compte (emails, contacts, calendriers, etc. selon ce que l’application a demandé). En fonction du choix de l’utilisateur, on pourra accéder ou non à ses informations.
Enregistrement de l’application
Il faut dans un premier temps enregistrer l’application sur https://manage.dev.live.com/ en cliquant sur Create Application. Il est nécessaire de renseigner un nom d’application (utilisé pour indiquer à l’utilisateur quelle est l’application qui souhaite accéder à ses informations) et de choisir une langue (utilisée pour afficher un message localisé à l’utilisateur).
![]()
L’application est alors référencée par Live ID.
![]()
Dans l’onglet API Settings de la page de configuration, on renseigne le domaine qui sera utilisé par Live ID pour effectuer une redirection (sans cette information, le SDK Interactive Live n’acceptera pas de renvoyer les informations).
![]()
Une fois l’enregistrement terminé, on va pouvoir depuis l’application envoyer une requête au SDK Live pour récupérer les informations nécessaires.
Il est possible de requêter ces informations de deux manières différentes: JavaScript ou REST.
Fédération Active – Contacter un service WCF fédéré
Lorsque l’on fait de la fédération d’identité, deux scénarios sont possibles pour authentifier un utilisateur: la fédération passive et la fédération active.
La fédération passive consiste à utiliser le protocole WS-Federation via les mécanismes HTTP de redirection et de POST (ce scénario convient donc plutôt à des applications Web). De cette manière, l’application ne possède aucune logique d’authentification et n’est pas responsable des données d’authentification de l’utilisateur.
Avec la fédération active, l’application possède la logique de récupération des données d’authentification de l’utilisateur et en est donc responsable. Le protocole WS-Trust est utilisé pour récupérer un token auprès du STS. Ce scénario convient donc à des applications de type service Windows contactant un service web fédéré.
La première étape lors d’une fédération active est donc de récupérer un token auprès du STS. Pour cela, le framework WIF fournit, dans le namespace Microsoft.IdentityModel.Protocols.WSTrust, l’interface IWSTrustContract permettant d’envoyer un message WS-Trust au STS, via la méthode Issue.
Récupération du token d’authentification
Ci-dessous le code illustrant la récupération d’un token en fédération active.
WSTrustChannelFactory factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress("https://my-sts.com/v2/wstrust/13/username"));
factory.Credentials.UserName.UserName = "demo";
factory.Credentials.UserName.Password = "demo";
factory.TrustVersion = TrustVersion.WSTrust13;
IWSTrustChannelContract proxy = factory.CreateChannel();
On crée une factory WSTrustChannelFactory en lui fournissant le binding correspondant au type d’authentification à utiliser (user/password, certificat, etc.) et l’adresse du endpoint du STS correspondant au binding (dans le code précédent, on authentifie l’utilisateur via un nom d’utilisateur et un mot de passe). Il faut alors renseigner les credentials et la version de WS-Trust à utiliser puis créer le proxy.
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress("https://my-domain.com/My-Application"),
KeyType = KeyTypes.Symmetric
};
Il est nécessaire d’instancier un RequestSecurityToken qui représente un token de demande. Pour recevoir un token d’authentification, il faut que le token de demande soit de type Issue et il faut renseigner l’URL de l’application pour laquelle le token doit être créé.
SecurityToken token = proxy.Issue(rst);
La méthode Issue du channel permet alors de récupérer un token SAML à partir du token de demande précédemment créé.
Accéder à la liste des actions d’un Controller depuis Javascript
L’une des nouveautés de ASP.NET MVC 3 est le support du Unobtrusive Javascript (Javascript discret en version française), c’est-à-dire le fait de ne plus embarquer de Javascript directement dans les pages web mais de les mettre dans des fichiers séparés.
L’un des problèmes liés à la séparation des pages web et du Javascript est de ne pas avoir accès aux Helper MVC dans les fichiers JS permettant notamment de générer des Url vers une action en fonction des routes déclarées : Url.Action(“Index”). La seule solution consiste à mettre en dur les URL dans le Javascript mais on perd l’aspect dynamique proposé par les routes MVC.
Ce post se base sur celui de Phil Haack qui proposait comme solution à cette problématique de générer dynamiquement un fichier JS contenant un helper permettant d’appeler une action en utilisant une URL sous la forme “/json/{controller}?invoke&action={action}”. De cette manière, il n’est plus nécessaire de mettre en dur dans le fichier JS l’URL de l’action, on peut à la place utiliser son helper en fournissant le nom du controller et le nom de l’action.
Le petit bémol de cette solution est qu’elle n’utilise pas d’URL « MVC compliant ». Je propose ici une modification de son implémentation pour ne plus générer un helper mais renvoyer l’URL liée à chaque action d’un controller sous la forme d’un dictionnaire Javascript. De cette manière, on pourra utiliser ce dictionnaire dans les fichiers JS pour faire référence à l’action en respectant les routes déclarées.
Custom Route, Custom Controller et Custom Action Invoker
La première étape de la solution est de créer une Custom Route qui permettra de différencier les routes « classiques » de notre route.
public class DiscoverableRoute : Route
{
public DiscoverableRoute(string url)
: base(url, new MvcRouteHandler())
{
if (url.IndexOf("{action}",
StringComparison.OrdinalIgnoreCase) > -1)
{
throw new ArgumentException("url");
}
}
public override VirtualPathData GetVirtualPath
(RequestContext requestContext,
RouteValueDictionary values)
{
return null;
}
}
Service WCF Claims Aware
De la même manière que pour une application ASP.NET, on peut utiliser la fédération d’identité pour sécuriser un service WCF.
On va voir dans ce post comment rendre un service WCF claims-aware, via l’utilitaire Windows Identity Foundation Federation Utility.
Windows Identity Foundation Federation Utility
Pour lancer l’utilitaire, cliquez droit, dans Visual Studio, sur Add STS reference… à partir d’un projet WCF (si l’utilitaire ne se lance pas, vous pouvez l’exécuter depuis le menu Administration Tools de Windows).

Le premier écran présente les informations sur notre service. On doit y renseigner l’emplacement du fichier de configuration (qui sera modifié par l’utilitaire) et l’URL du service.
![]()
Le deuxième écran permet de sélectionner le STS responsable de l’authentification. Pour utiliser ACS (Access Control Service, STS version Cloud de Microsoft) ou ADFS (Active Directory Federation Services, STS version On-Premise de Microsoft), on doit sélectionner l’option Use an existing STS et renseigner l’adresse du fichier FederationMetadata.xml du STS, fichier contenant les informations de configuration.

L’écran suivant permet d’activer le cryptage du token SAML (obligatoire pour un service WCF) en fournissant un certificat.
![]()
Après validation, l’utilitaire va modifier le fichier de configuration de notre service.
Etendre IIS Manager
IIS 7 fournit un mécanisme d’extensibilité permettant aux développeurs d’intégrer leurs propres interfaces à IIS Manager. Ces interfaces sont appelés module IIS et sont exploités notamment par Web Platform Installer et par App Fabric.

Icône du module Web Platform Installer

IHM du module Web Platform Installer

Icônes du module AppFabric

IHM du module AppFabric
Attention à ne pas confondre module IIS et module HTTP. Un Module IIS est une application qui va s’intégrer dans IIS Manager et donc étendre ses fonctionnalités. Un Module HTTP est une assembly qui est appelée à chaque requête effectuée sur une application web. Ces modules ont des rôles totalement différents.
Nous allons voir comment créer notre propre module IIS.



