User Name Password Validator
Cet exemple montre comment implémenter un validateur UserNamePassword personnalisé. Cela s'avère utile dans les cas où aucun des modes de validation UserNamePassword intégrés ne convient aux spécifications de l'application ; par exemple, lorsque les paires nom d'utilisateur/mot de passe sont stockées dans quelque magasin externe, tel qu'une base de données. Cet exemple illustre un service qui comprend un validateur personnalisé qui vérifie pour deux paires nom d'utilisateur/mot de passe particulières. Le client utilise une paire nom d'utilisateur/mot de passe pour s'authentifier auprès du service.
Remarque : |
---|
Étant donné que n'importe qui peut générer une information d'identification de nom d'utilisateur qui utilise les paires nom d'utilisateur/mot de passe acceptées par le validateur personnalisé, le service est moins sécurisé que le comportement par défaut fourni par le validateur UserNamePassword standard. Le validateur UserNamePassword standard essaie de mapper la paire nom d'utilisateur/mot de passe fournie à un compte Windows et fait échouer l'authentification si ce mappage échoue. Le validateur UserNamePassword personnalisé dans cet exemple NE DOIT PAS être utilisé dans le code de production ; il est fourni à titre d'illustration uniquement. |
En résumé, cet exemple montre comment :
- Le client peut être authentifié à l'aide d'un jeton de nom d'utilisateur ;
- Le serveur valide les informations d'identification du client à l'aide d'un UserNamePasswordValidator personnalisé et comment propager les erreurs personnalisées de la logique de validation du nom d'utilisateur et du mot de passe au client ;
- Le serveur est authentifié à l'aide du certificat X.509 du serveur.
Le service expose un point de terminaison unique permettant de communiquer avec le service, défini à l'aide du fichier de configuration App.config. Le point de terminaison se compose d'une adresse, d'une liaison et d'un contrat. La liaison est configurée avec une wsHttpBinding standard qui a comme valeur par défaut l'utilisation de WS-Security et l'authentification du nom d'utilisateur. Le comportement de service spécifie le mode Custom pour valider les paires nom d'utilisateur/mot de passe du client avec le type de la classe de validateur. Le comportement spécifie également le certificat de serveur à l'aide de l'élément serviceCertificate. Le certificat de serveur doit contenir la même valeur pour le SubjectName que la findValue dans l'serviceCertificate element of serviceCredentials.
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.CalculatorService"
behaviorConfiguration="CalculatorServiceBehavior">
<!-- use host/baseAddresses to configure base address provided by host -->
<host>
<baseAddresses>
<add baseAddress ="https://localhost:8001/servicemodelsamples/service" />
</baseAddresses>
</host>
<!-- use base address specified above, provide one endpoint -->
<endpoint address="username"
binding="wsHttpBinding"
bindingConfiguration="Binding"
contract="Microsoft.ServiceModel.Samples.ICalculator" />
</service>
</services>
<bindings>
<wsHttpBinding>
<!-- username binding -->
<binding name="Binding">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceDebug includeExceptionDetailInFaults ="true"/>
<serviceCredentials>
<!--
The serviceCredentials behavior allows one to
specify a custom validator for username/password
combinations.
-->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService+MyCustomUserNameValidator, service" />
<!--
The serviceCredentials behavior allows one to define a service certificate.
A service certificate is used by a client to authenticate the service and provide message protection.
This configuration references the "localhost" certificate installed during the setup instructions.
-->
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
La configuration de point de terminaison de client se compose d'un nom de configuration, d'une adresse absolue pour le point de terminaison de service, de la liaison et du contrat. La liaison de client est configurée avec le mode et le message clientCredentialType appropriés.
<system.serviceModel>
<client>
<!-- Username based endpoint -->
<endpoint name="Username"
address="https://localhost:8001/servicemodelsamples/service/username"
binding="wsHttpBinding"
bindingConfiguration="Binding"
behaviorConfiguration="ClientCertificateBehavior"
contract="Microsoft.ServiceModel.Samples.ICalculator">
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<!-- Username binding -->
<binding name="Binding">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<serviceCertificate>
<!--
Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
is in the user's Trusted People store, then it will be trusted without performing a
validation of the certificate's issuer chain. This setting is used here for convenience so that the
sample can be run without having to have certificates issued by a certification authority (CA).
This setting is less secure than the default, ChainTrust. The security implications of this
setting should be carefully considered before using PeerOrChainTrust in production code.
-->
<authentication certificateValidationMode="PeerOrChainTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
L'implémentation cliente invite l'utilisateur à entrer un nom d'utilisateur et un mot de passe.
// Get the username and password
Console.WriteLine("Username authentication required.");
Console.WriteLine("Provide a username.");
Console.WriteLine(" Enter username: (test1)");
string username = Console.ReadLine();
Console.WriteLine(" Enter password:");
string password = "";
ConsoleKeyInfo info = Console.ReadKey(true);
while (info.Key != ConsoleKey.Enter)
{
if (info.Key != ConsoleKey.Backspace)
{
if (info.KeyChar != '\0')
{
password += info.KeyChar;
}
info = Console.ReadKey(true);
}
else if (info.Key == ConsoleKey.Backspace)
{
if (password != "")
{
password = password.Substring(0, password.Length - 1);
}
info = Console.ReadKey(true);
}
}
for (int i = 0; i < password.Length; i++)
{
Console.Write("*");
}
Console.WriteLine();
// Create a proxy with Certificate endpoint configuration
CalculatorProxy proxy = new CalculatorProxy("Username")
try
{
proxy.ClientCredentials.Username.Username = username;
proxy.ClientCredentials.Username.Password = password;
// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = proxy.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
}
catch (Exception e)
{
Console.WriteLine("Call failed:");
while (e != null)
{
Console.WriteLine("\t{0}", e.Message);
e = e.InnerException;
}
proxy.Abort();
}
}
Cet exemple utilise un UserNamePasswordValidator personnalisé pour valider des paires nom d'utilisateur/mot de passe. L'exemple implémente CustomUserNamePasswordValidator
, dérivé de UserNamePasswordValidator. Pour plus d'informations, consultez la documentation de UserNamePasswordValidator. Cet exemple de validateur personnalisé particulier implémente la méthode Validate
pour accepter deux paires nom d'utilisateur/mot de passe particulières, comme le montre le code suivant.
public class CustomUserNameValidator : UserNamePasswordValidator
{
// This method validates users. It allows in two users,
// test1 and test2 with passwords 1tset and 2tset respectively.
// This code is for illustration purposes only and
// MUST NOT be used in a production environment because it
// is NOT secure.
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
{
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
Une fois que le validateur est implémenté dans le code de service, l'hôte de service doit être informé de l'instance de validateur à utiliser. Cela est effectué à l'aide du code suivant.
serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceHost.Credentials. UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNamePasswordValidator();
Vous pouvez faire la même chose dans la configuration comme suit.
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
...
<serviceCredentials>
<!--
The serviceCredentials behavior allows one to specify authentication constraints on username / password combinations.
-->
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService+CustomUserNameValidator, service" />
...
</behavior>
</serviceBehaviors>
</behaviors>
Lorsque vous exécutez l'exemple, les demandes et réponses d'opération s'affichent dans la fenêtre de console cliente. Le client doit appeler toutes les méthodes avec succès. Appuyez sur ENTER dans la fenêtre du client pour l'arrêter.
Fichier de commandes d'installation
Le fichier de commandes Setup.bat inclus avec cet exemple permet de configurer le serveur avec les certificats pertinents pour exécuter une application auto-hébergée qui requiert une sécurité basée sur le certificat du serveur. Ce fichier doit être modifié pour fonctionner sur plusieurs ordinateurs ou dans un cas non hébergé.
Les éléments suivants fournissent une brève vue d'ensemble des différentes sections des fichiers de commandes afin qu'ils puissent être modifiés pour s'exécuter dans la configuration appropriée.
Création du certificat de serveur :
Les lignes suivantes du fichier de commandes Setup.bat génèrent le certificat de serveur à utiliser. La variable %SERVER_NAME% spécifie le nom du serveur. Modifiez-la pour spécifier votre propre nom de serveur. La valeur par défaut est localhost.echo ************ echo Server cert setup starting echo %SERVER_NAME% echo ************ echo making server cert echo ************ makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
Installation du certificat de serveur dans le magasin de certificats approuvés du client :
Les lignes suivantes du fichier de commandes Setup.bat copient le certificat de serveur dans le magasin de personnes de confiance du client. Cette étape est requise car les certificats générés par Makecert.exe ne sont pas implicitement approuvés par le système client. Si vous disposez déjà d'un certificat associé à un certificat racine approuvé du client, par exemple un certificat émis par Microsoft, cette étape de remplissage du magasin de certificats clients avec le certificat de serveur n'est pas requise.certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
Pour configurer et générer l'exemple
Pour générer la solution, suivez les instructions indiquées dans la rubrique Génération des exemples Windows Communication Foundation.
Pour exécuter l'exemple dans une configuration à un ou plusieurs ordinateurs, suivez les instructions ci-dessous.
Pour exécuter l'exemple sur le même ordinateur
Assurez-vous que le chemin d'accès inclut le dossier dans lequel Makecert.exe se trouve.
Exécutez Setup.bat à partir du dossier d'installation de l'exemple. Tous les certificats requis pour l'exécution de l'exemple sont ainsi installés.
Lancez Service.exe dans service\bin.
Lancez Client.exe à partir de \client\bin. L'activité du client s'affiche sur son application de console.
Si le client et le service ne parviennent pas à communiquer, consultez Conseils de dépannage.
Pour exécuter l'exemple sur plusieurs ordinateurs
Créez un répertoire sur l'ordinateur de service pour les fichiers binaires du service.
Copiez les fichiers programme du service dans le répertoire de service sur l'ordinateur de service. Copiez également les fichiers Setup.bat et Cleanup.bat sur l'ordinateur de service.
Il vous faut un certificat de serveur dont le nom du sujet contient le nom de domaine complet de l'ordinateur. Le fichier de configuration pour le serveur doit être mis à jour pour refléter ce nouveau nom de certificat.
Copiez le certificat de serveur dans le magasin CurrentUser-TrustedPeople du client. Cette tâche est requise uniquement si le certificat du serveur n'est pas publié par un émetteur approuvé.
Dans le fichier App.config sur l'ordinateur de service, modifiez la valeur de l'adresse de base afin de remplacer localhost par un nom d'ordinateur complet.
Sur l'ordinateur de service, lancez Service.exe à partir d'une fenêtre d'invite de commandes.
Copiez les fichiers programme du client du dossier \client\bin\ (situé dans le dossier correspondant à votre langue) sur l'ordinateur client.
Dans le fichier Client.exe.config sur l'ordinateur client, modifiez la valeur d'adresse du point de terminaison afin qu'elle corresponde à la nouvelle adresse de votre service.
Sur l'ordinateur client, lancez Client.exe à partir d'une fenêtre d'invite de commandes.
Si le client et le service ne parviennent pas à communiquer, consultez la rubrique Conseils de dépannage.
Pour procéder au nettoyage après exécution de l'exemple
- Exécutez Cleanup.bat dans le dossier d'exemples après avoir exécuté l'exemple. Cela supprime le certificat de serveur du magasin de certificats.
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.