6.28.2012

Implementando un Foreach con expresión Lambda

En días pasados dando una capacitación, le solicité al grupo de desarrolladores que hicieran un método que recibiera una lista de clientes y un parámetro tipo string –> en este caso el país –> para filtrar la lista con este parámetro y retornar otra lista con los clientes que pertenecen al país solicitado. Como era de esperarse, la mayoría de los estudiantes solucionó el problema con un foreach y haciendo una comparación en cada iteración. Sin embargo, creo que es mucho más simple implementar esta solución a través de una expresión lambda y es lo que me llevó a escribir este post.

En primera instancia vamos a escribir la clase cliente sobre la cual vamos a llevar a cabo el procedimiento.

public class Cliente
{
public int Id { get; set; }
public string Nombre { get; set; }
public string Apellido1 { get; set; }
public string Apellido2 { get; set; }
public string Pais { get; set; }
}

Ahora procedemos a escribir el método que recibirá la lista de clientes y procederá a retornar otra lista filtrada con el parámetro número 2 –> el país de donde quiero los clientes.

public List<Cliente> ObtenerPorPais(List<Cliente> pLista, string pPais)
{
return pLista.Where(p => p.Pais == pPais).ToList();
}

En este código se va a comprara cada uno de los elementos de la lista, y los que cumplan con la condición ( p.Pais == pPais) serán retornados en una lista cuyo tipo se infiere a partir del tipo de la lista original y de la invocación del método ToList().


Como podemos ver en el método anterior, es mucho más simple implementar la solución con una expresión lambda y un método de extensión de linq que utilizar un foreach y una comparación por cada elemento de forma manual.



Etiquetas de Technorati: ,,,,

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: ,

6.17.2012

Autenticando Servicios WCF – Certificados Digitales–Parte 2

En el post anterior empezamos creando el certificado digital e instalándolo de forma tal que pueda ser utilizado para autenticar un cliente a la hora de consumir un servicio utilizando WCF. Ahora vamos a proceder a crear un servicio que utilice este certificado como medio de autenticación.

Creando el Servicio WCF que Utiliza el Certificado Digital

Para iniciar vamos a crear un servicio WCF con la plantilla de proyecto “WCF Service Library”.

image

Ahora vamos a crear un contrato de servicio con una simple operación que suma dos número –> la complejidad del servicio no es relevante, incluso pudimos utilizar el servicio pre generado.

using System.ServiceModel;

namespace ServicioSeguroBlog
{
[ServiceContract(Namespace="http://www.formsevolution.com")]
public interface IServicioSeguro
{
[OperationContract]
int Sumar(int pX, int pY);
}
}


Y procedemos a implementar el servicio

namespace ServicioSeguroBlog
{
public class ServicioSeguro : IServicioSeguro
{
public int Sumar(int pX, int pY)
{
return pX + pY;
}
}
}

Ahora procedemos a configurar el servicio de forma tal que pueda utilizar el certificado para la autenticación. El primer paso es definir un “binding” para establecer como se va a manejar la seguridad en el endpoint, esta seguridad se define por tipo de protocolo a utilizar –> podemos tener múltiples configuraciones para cada binding ya que siempre los podemos identificar vía el nombre. Como se puede ver en el siguiente código, en este binding vamos a utilizar seguridad a nivel de mensaje y el tipo de credencial a utilizar será certificado.

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

El siguiente paso es modificar el comportamiento estándar definido para el endpoint por parte de la plantilla de WCF para establecer como se van a manejar los certificados a la hora de autenticar. En primera instancia, al estar utilizando un certificado temporal tenemos que habilitar el revocationMode. Seguidamente configuramos el certificado a nivel de servicio para indicarle el nombre de mismo, su ubicación, y el nombre del almacén que lo contiene.

        <behavior>
<
serviceMetadata httpGetEnabled="True"/>
<
serviceDebug includeExceptionDetailInFaults="False" />
<
serviceCredentials>
<
clientCertificate
>
<
authentication revocationMode="NoCheck"
/>
</
clientCertificate
>
<
serviceCertificate findValue="CN=DRMCert" storeLocation="LocalMachine" storeName="My"
/>
</
serviceCredentials
>
</
behavior>

Por último procedemos a “ligar” el endpoint del servicio con los ítems configurados anteriormente.

      <service name="ServicioSeguroBlog.ServicioSeguro">
<
host>
<
baseAddresses>
<
add baseAddress = "http://localhost:8732/Design_Time_Addresses/ServicioSeguroBlog/Service1/" />
</
baseAddresses>
</
host>
<
endpoint address ="" bindingConfiguration="wsHttpEndpointBinding" binding="wsHttpBinding" contract="ServicioSeguroBlog.IServicioSeguro">
<
identity>
<
dns value="localhost"/>
</
identity>
</
endpoint>
<
endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</
service>

A nivel del comportamiento no es necesario agregarle nada ya que el servicio utiliza el que esta definido por defecto, por lo tanto solo tenemos que agregar el binding el cual hacemos a través de la etiqueta bindingConfiguration. Ahora procedemos a instalar el servicio en el IIS.


Antes de instalar el servicio podemos probar que este este funcionando correctamente con el host temporal de VS 2010 –> svcHost. Si el servicio carga esta bien configurado.


image


Sin embargo, si lo ejecutamos debe de fallar ya que el cliente de prueba auto configurado no tiene la información del certificado para autenticarse.


image


Para instalar el servicio, hacemos una aplicación web dentro del IIS


image


Seguidamente creamos un Application Pool que tenga un usuario que tenga permisos para acceder al certificado, en mi caso es usuario local –> Local System.


image


Luego procedemos a asignar ese pool a la nueva aplicación web.


image


El siguiente paso es instalar el servicio en la nueva aplicación creada en el IIS. Esto se hace seleccionado la opción de publicar el servicio.


image


El VS nos dirá si la instalación estuvo correcta o no.


image


Si habilitamos el directory browsing y vamos a la dirección del servicio vamos a ver el contenido del directorio.


image


si le damos click al archivo svc veremos la presentación del servicio y ahí podemos seleccionar ver el wsdl del servicio.


image




Configurar el Cliente


El último paso es configurar el cliente. Para esto vamos a crear una aplicación de consola que va a consumir el servicio. El primer paso es agregar la referencia al servicio con la dirección del WSDL.


image


Seguidamente procedemos a codificar la invocación a la operación.


 

using System;
using ClienteSeguro.ReferenciaServicio;

namespace ClienteSeguro
{
class Program
{
static void Main()
{
using (var _proxy = new ServicioSeguroClient())
{
var _resultado = _proxy.Sumar(3, 5);
Console.WriteLine(_resultado);
}
}
}
}

El siguiente paso es configurar el cliente para que pueda autenticarse con el certificado. Primeramente procedemos a agregar el comportamiento del lado del cliente para que el cliente sepa donde esta el certificado a utilizar. En este caso será igual del servicio porque estamos haciendo el ejercicio en la misma máquina, en situaciones reales hay que instalar el certificado en el cliente e indicar en la configuración en donde se encuentra este certificado.

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








Por último agregamos el comportamiento al endpoint del servicio.

      <endpoint address="http://diego-pc.cgccr.priv/WCFCertificados/ServicioSeguroBlog.ServicioSeguro.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServicioSeguro" behaviorConfiguration="BehaviorNuevo"
contract="ReferenciaServicio.IServicioSeguro" name="WSHttpBinding_IServicioSeguro">
<
identity>
<
certificate encodedValue="AwAAAAEAAAAUAAAALKVZNNCYWPMn+f6f4SfBghH+PcIgAAAAAQAAAOwBAAAwggHoMIIBVaADAgECAhBZhs7Ez8SQt0Ud2V9N1dnOMAkGBSsOAwIdBQAwEjEQMA4GA1UEAxMHUm9vdERSTTAeFw0xMjA1MTYxNzQyMjBaFw0zOTEyMzEyMzU5NTlaMBIxEDAOBgNVBAMTB0RSTUNlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALG6+TrqsTKkBSNpfbpKHQGzdV8poX7+0fMf5/3jdrkFz1FnfZ7VmmMPIxdNuYJv63B2ScofpZEyvOfw61DHvjShORUSk3kw5NUW40hpVx4KUSneJjcvXklIHdODUfsCy7Werx30Q0CsgfydtCzJkKYLCuT3WVFxHeIqjNRFzIuzAgMBAAGjRzBFMEMGA1UdAQQ8MDqAEEPdF141cN5jkiYGrl1aJRChFDASMRAwDgYDVQQDEwdSb290RFJNghBrRb3C05OyokfF03CEBc6QMAkGBSsOAwIdBQADgYEAl+fRGhfd/gxgmtDLUFJ2UnAPII6lslW5hMeSs/VPXpCafoOzJSfBV3NPXMslTHKgRrBfuRwcf3ruID5Ttas5n1JPfvzn7TYqVDQ+vU2rOt0A19FAMMGJBW9Q934NxRVwPSR6Yklpunozb3EFg/YdVTcBbrr658wKN/O8hrGl+IM=" />
</
identity>
</
endpoint>

Si ejecutamos el cliente anterior el resultado es el siguiente:


image


Etiquetas de Technorati: ,