6.24.2012

Autenticando Servicios WCF – Certificados Digitales y Usuario/Password –Parte 3

Continuando con la serie de posts acerca de la autenticación de servicios, en este post vamos a proceder a realizar la autenticación de un servicio WCF vía usuario y password. En estos casos siempre es recomendable utilizar un certificado para asegurar el canal ya que de lo contrario, estaríamos enviando las credenciales en “clear text” y esto conlleva a que nos podamos ver en problemas si nos interceptan el mensaje.

Esquema usuario y password

Para este post vamos a utilizar una base de datos de usuarios muy conocida por los desarrolladores .NET y en especial los que utilizan mucho ASP.NET: ASPNETDB. Esta base de datos es generada a partir de un esquema que ya se encuentra incluido en los directorios de .NET y normalmente se accede utilizando el Sql Membership Provider –> Para más información acerca del ASPNETDB y el SQL Membership Provider visitar el siguiente sitio web. El esquema básico de esta base de datos con las características de usuarios y roles se ve en la siguiente figura:

image

Luego volveremos para poder agregar usuarios en la base de datos seleccionada. Por ahora proseguiremos con la implementación del servicio.

Crear el Servicio

En este caso vamos a crear un servicio muy simple que tiene una operación que recibe un string y retorna un decimal. El contrato del servicio es el siguiente:

using System.ServiceModel;

namespace AutenticacionUP
{
[ServiceContract(Namespace="http://icomparable.blogspot.com")]
public interface IServicioCuentasBancarias
{
[OperationContract]
decimal ObtenerSaldo(string pNumeroCuenta);
}
}

Seguidamente procedemos con la implementación del servicio.

namespace AutenticacionUP
{
public class ServicioCuentasBancarias : IServicioCuentasBancarias
{
public decimal ObtenerSaldo(string pNumeroCuenta)
{
return 394232;
}
}
}

Ahora procedemos a configurar el servicio. El primer paso es configurar el endpoint y probar el servicio en el test client.

      <service name="AutenticacionUP.ServicioCuentasBancarias">
<
host>
<
baseAddresses>
<
add baseAddress = "http://localhost:8732/Design_Time_Addresses/AutenticacionUP/Service1/" />
</
baseAddresses>
</
host>
<
endpoint address ="" binding="wsHttpBinding" contract="AutenticacionUP.IServicioCuentasBancarias">
</endpoint>
<
endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</
service>

El servicio corriendo es el siguiente:


image


Ahora procedemos a configurar la seguridad del servicio. El primer paso es crear un binding en donde se especifica el tipo de seguridad que vamos a manejar para autenticar el servicio.

    <bindings>
<
wsHttpBinding>
<
binding name="wsHttpEndpointBinding">
<
security>
<
message clientCredentialType="UserName" />
</
security>
</
binding>
</
wsHttpBinding>
</
bindings>

Como podemos ver en el binding, vamos a especificar que la seguridad a nivel de mensaje se llevará a cabo usando el nombre usuario y password como tipo de credencial del cliente. Ahora procedemos a asociar la credencial al servicio.

<endpoint address ="" binding="wsHttpBinding" 
bindingConfiguration="wsHttpEndpointBinding" contract="AutenticacionUP.IServicioCuentasBancarias">

Ahora procedemos a modificar el comportamiento estándar del servicio para que utilice el certificado que vamos a especificar para que asegure el canal. Este certificado estará disponible en la máquina local y en el almacén My. Nótese además que le estamos indicando que la autenticación a utilizar es userNameAuthentication y que vamos a utilizar un membershipProvider llamar MySqlMembershipProvider.

        <behavior>
<
serviceMetadata httpGetEnabled="true" />
<
serviceDebug includeExceptionDetailInFaults="false" />
<
serviceCredentials>
<
serviceCertificate findValue="CN=DRMCert" storeLocation="LocalMachine" storeName="My" />
<
userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="MySqlMembershipProvider"
/>
</
serviceCredentials
>
</
behavior>

WCF soporta por defecto el uso del SQL Membership provider. Para poder utilizar tenemos que configurarlo en el app.config del servicio.

<configuration>
<
connectionStrings>
<
add name="MyLocalSQLServer"
connectionString="Initial Catalog=aspnetdb; data source=.\sqlexpress;Integrated Security=SSPI;" />
</
connectionStrings>
<
system.web>
<
compilation debug="true" />
<
membership defaultProvider="MySqlMembershipProvider" >
<
providers>
<
clear/>
<
add name="MySqlMembershipProvider"
connectionStringName="MyLocalSQLServer"
applicationName="MyAppName"
type="System.Web.Security.SqlMembershipProvider" />
</
providers>
</
membership>
</
system.web>

En este le vamos a indicar en que instancia de base de datos está la base de datos y además vamos a configurar el membership provider. En este vamos a definir el connection string que debe de utilizar para conectarse y además el nombre del provider, el cual será utilizado por el behavior configurado anteriormente para realizar la autenticación.


Ahora procedemos a instalar el servicio. Probamos que el mismos esté disponible navegando hasta la ubicación del servicio svc.


image


Ahora procedemos con el cliente. Para esto procedemos con una aplicación de consola, desde la cual agregamos una referencia al servicio que estamos elaborando:


image


Ahora consumimos el servicio de la forma que normalmente lo hacemos, sin embargo esta vez, vamos a tener que agregar el usuario y el password que para nuestro caso ya fueron agregados a la base de datos del membershipProvider –> para agregar usuarios a esta base de datos lo mejor es crear una aplicación web y desde ahi levantar el sitio web de configuración del sitio, desde donde es muy simple agregar los usuarios.

using System;
using ClienteUP.ServicioCuentasBancarias;

namespace ClienteUP
{
class Program
{
static void Main()
{
using (var _proxy = new ServicioCuentasBancariasClient())
{
_proxy.ClientCredentials.UserName.UserName = "prueba";
_proxy.ClientCredentials.UserName.Password = "Pa$$word1";

var _resultado = _proxy.ObtenerSaldo("22222");
Console.WriteLine(_resultado);
}
}
}
}

El último paso es configurar el servicio del lado del cliente para que utilice el certificado para poder comunicarse de forma segura con el servicio. Primero configuramos el comportamiento en donde le decimos al servicio donde obtener el certificado.

      <behaviors>
<
endpointBehaviors>
<
behavior name="BehaviorNuevo">
<
clientCredentials>
<
clientCertificate findValue="CN=DRMCert"
storeLocation="LocalMachine"
storeName="My" />
<
serviceCertificate>
<
authentication revocationMode="NoCheck"/>
</
serviceCertificate>
</
clientCredentials>
</
behavior>
</
endpointBehaviors>
</
behaviors>

 


Ahora procedemos a agregar el behavior al endpoint del servicio:

        <client>
<
endpoint address="http://diego-pc/WCFCertificados/AutenticacionUP.ServicioCuentasBancarias.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServicioCuentasBancarias"
behaviorConfiguration="BehaviorNuevo"
contract="ServicioCuentasBancarias.IServicioCuentasBancarias"
name="WSHttpBinding_IServicioCuentasBancarias">
<
identity>
<
certificate encodedValue="AwAAAAEAAAAUAAAALKVZNNCYWPMn+f6f4SfBghH+PcIgAAAAAQAAAOwBAAAwggHoMIIBVaADAgECAhBZhs7Ez8SQt0Ud2V9N1dnOMAkGBSsOAwIdBQAwEjEQMA4GA1UEAxMHUm9vdERSTTAeFw0xMjA1MTYxNzQyMjBaFw0zOTEyMzEyMzU5NTlaMBIxEDAOBgNVBAMTB0RSTUNlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALG6+TrqsTKkBSNpfbpKHQGzdV8poX7+0fMf5/3jdrkFz1FnfZ7VmmMPIxdNuYJv63B2ScofpZEyvOfw61DHvjShORUSk3kw5NUW40hpVx4KUSneJjcvXklIHdODUfsCy7Werx30Q0CsgfydtCzJkKYLCuT3WVFxHeIqjNRFzIuzAgMBAAGjRzBFMEMGA1UdAQQ8MDqAEEPdF141cN5jkiYGrl1aJRChFDASMRAwDgYDVQQDEwdSb290RFJNghBrRb3C05OyokfF03CEBc6QMAkGBSsOAwIdBQADgYEAl+fRGhfd/gxgmtDLUFJ2UnAPII6lslW5hMeSs/VPXpCafoOzJSfBV3NPXMslTHKgRrBfuRwcf3ruID5Ttas5n1JPfvzn7TYqVDQ+vU2rOt0A19FAMMGJBW9Q934NxRVwPSR6Yklpunozb3EFg/YdVTcBbrr658wKN/O8hrGl+IM=" />
</
identity>
</
endpoint>
</
client>

El resultado al ejecutar el servicio es el siguiente:


image


Etiquetas de Technorati: ,

No hay comentarios: