Monthly Archives: May 2008

Amy "what a waste" Winehouse

Yesterday I saw one of the worst live performances I can remember. Amy Winehouse has a fantastic voice, but if she keeps doing this she will disappear from scene within the next six months. As if starting the concert 45 minutes after time wasn”t bad enough, she appeared completely drunk (and, dare I say it, stoned?).

Her voice was really awful and she even fell on stage. Thank god her band is really amazing (well, if it weren”t for the guys on the chorus she would probably be lying on the floor!) and tried to compensate for her unprofessional behavior.

This is one of those things that really makes me mad. There are so many people out there trying to be superstars and they just can”t get there (even when they”re trying hard). On the other hand, we have people like Amy: they already have everything (man, even with a sour voice, there really isn”t any doubts that she really can sing) and it looks like they don”t give a crap about it and don”t mind simply throwing everything away.

Acceder a la caché de Internet Explorer (IV)

windowsservice

En los dos primeros artículos pudimos ver los objetos del API de Windows que íbamos a usar para poder acceder a la caché de los archivos temporales de Internet, cómo persistir estos datos en formato XML, y finalmente cómo permitir que temporalmente nuestra aplicacación se ejecute con las credenciales de otro usuario, para poder realizar una serie de acciones que de otro modo no podría efectuar por falta de privilegios.

Siguiendo con el objetivo de este ejercicio hoy vamos a encapsular la lógica de negocio de nuestra aplicación en forma de servicio de Windows, y éste va a encargarse de realizar una consulta a la caché de Internet de nuestro ordenador cada X tiempo (configurable mediante un fichero XML).

Lo primero de todo va a ser construir la base de nuestro servicio mediante un proyecto de tipo Windows Service. Esta plantilla nos genera un proyecto con un componente de tipo ServiceBase, que servirá para ir construyendo nuestro pequeño juguetito.

CreateWindowsService

A continuación vamos a cambiar el nombre al servicio, en nuestro caso lo llamaremos “IECacheQueryService”. Y posteriormente estableceremos a True los valores de las propiedades CanPauseAndContinue y CanShutdown, para poder pausar y detener nuestro servicio en tiempo de ejecución.

Importante: Comprobar que el nombre sel servicio se ha cambiado correctamente en el punto de entrada de la aplicación (si no fuese así tendremos que modificarlo manualmente):

static class Program
    {
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new IECacheQueryService() 
            };
 
            ServiceBase.Run(ServicesToRun);
        }
    }

Implementando funcionalidad al servicio:


De momento el servicio será capaz de iniciarse, pero no realizará nada. Ahora debemos dotarlo de funcionalidad, y para ello vamos a crear un temporizador que se encargue de realizar una tarea cada X tiempo (por defecto una hora). Éste lo crearemos como un miembro dentro de nuestra clase:


public partial class IECacheQueryService : ServiceBase
{
    private Timer clock = new Timer();

Y lo usaremos desde el constructor de la misma, así como en los eventos OnStart y OnStop. Observar que en el constructor lo inicializamos con un valor que proviene del fichero de configuración del proyecto (propiedades del proyecto/settings) llamado TimerInterval y se ha establecido a un valor de 3.600.000 (1 hora en milisegundos).


public IECacheQueryService()
{
    InitializeComponent();
 
    clock = new Timer(Properties.Settings.Default.TimerInterval);
    clock.Elapsed += new ElapsedEventHandler(clock_Elapsed);
    clock.Enabled = true;
    //...
}
 
 
protected override void OnStart(string[] args)
{           
    ExecuteQuery();
    clock.Start();
    //...
}
 
protected override void OnStop()
{
    clock.Stop();
}

Del mismo modo también especificamos el manejador de evento asociado que se ejecutará cada vez que se cumpla este intervalo de tiempo (clock_Elapsed). Éste será el corazón de nuestro servicio y será el encargado de invocar la consulta a la caché de IE:


void clock_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            ExecuteQuery();
        }
        catch (Exception ex)
        {
            appEventLog.WriteEntry("Exception: " + ex.Message,
                EventLogEntryType.Error);
        }
    }

Simple verdad? Ahora vamos a construir este método ExecuteQuery a apartir de las piezas que vimos en anteriores entradas de la misma serie. No os preocupeis que en el último post estará un enlace al código completo del ejemplo (incluido el instalable).


Que hace exactamente este método?


  • Primero de todo crea un objeto de tipo StopWatch para medir con precisión el tiempo que transcurre en la ejecución del mismo.
  • Llama al método getResults que se encarga de efectuar la consulta y devolver un objeto que es una lista genérica de entradas de la caché.
  • Construye el nombre de fichero en el que guardaremos los resultados y llama al método saveResults, encargado de realizar la suplantación de identidad y serializar los resultados en el fichero antes mencionado.

private void ExecuteQuery()
{
    try
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        List<IECacheEntry> results = getResults(
            Properties.Settings.Default.SearchPattern);
        string filename = string.Format("{0}{1}_{2}.xml",
            Properties.Settings.Default.TargetPathLocation,
            Environment.MachineName,
            DateTime.Now.ToString("ddMMyyyy_hhmm"));
        watch.Stop();
        TimeSpan ts = watch.Elapsed;
        saveResults(results, filename);
        appEventLog.WriteEntry(string.Format(
            "Query executed successfully at {0} in '{1}' by user '{2}'. Elapsed time (ms): {3}",
            DateTime.Now.ToString(), Environment.MachineName,
            WindowsIdentity.GetCurrent().Name,ts.Milliseconds));
    }
    catch (Exception ex)
    {
        appEventLog.WriteEntry("Exception: " + ex.Message,
            EventLogEntryType.Error);
    }
}

Está el servicio terminado? Bueno, si asumimos que el código está completo y funciona sin errores, sí, lo está :-P


Y ahora cómo lo probamos? Pues… bueno, para probarlo antes tenemos que instalarlo.


Agregando los elementos necesarios para instalar el servicio:


No he encontrado demasiada documentación al respecto, de modo que intentaré mostrar los pasos a seguir mediante capturas de pantalla.


Vamos a agregar un elemento que nos permita distribuir el servicio:


AddInstallerClass


Le agregaremos dos componentes serviceProcessInstaller y serviceInstaller (es posible que no aparezcan en la barra de herramientas, así que tendremos que agregarlos mediante la opción “Choose Items…”


InstallerComponents


A continuación los configuraremos del siguiente modo:


Control Propiedad Valor
serviceProcessInstaller1 Account LocalSystem (*)
serviceProcessInstaller1 Parent Installer1
serviceInstaller1 Description Internet Explorer Query Cache
serviceInstaller1 Display Name Internet Explorer Query Cache
serviceInstaller1 Parent Installer1
serviceInstaller1 ServiceName IEQueryCache
serviceInstaller1 StartType Automatic

(*) Habitualmente se utilizará siempre la cuenta con menos nivel de privilegios (LocalService), pero en nuestro caso necesitamos acceder a la caché de IE, de modo que es posible que incluso tengamos que configurar la cuenta de un usuario de windows con suficientes permisos.


Cruzamos los dedos, compilamos el proyecto y vamos a agegar un proyecto de instalación a la solución.


Creando el proyecto de instalación:


Agregaremos un proyecto de tipo Setup and deployment, que será el encargado de instalar nuestro servicio en las estaciones Windows que deseamos monitorizar.


CreateSetupProject


Agregamos la salida del proyecto anterior al nuevo proyecto de instalación:


AddProjectOutput


AddProjectOutputDialog


Ahora mostraremos la ventana de “custom actions” para agregar como acción al instalador la salida de nuestro proyecto de servicio de Windows.


AddCustomAction


AddCustomActionDialog


Una vez realizado esto ya podemos compilar el proyecto de instalación e instalarlo en las estaciones cliente. Si quereis instalarlo en vuestra estación para probarlo y configurarlo adecuadamente, la opción más sencilla es seleccionar la opción Install del menú contextual del proyecto de instalación, en el explorador de proyectos.


Setup


Una vez instalado, aparecerá en el administrador de servicios, para que podamos configurarlo del modo deseado. En este caso particular, si deseamos monitorizar la caché de un usuario en particular, deberemos usar las credenciales de éste usuario, ya que si no el S.O. no será capaz de montar el fichero Index.dat correspondiente a la caché de Internet Explorer.


AdminServices


Bueno, hasta aquí ha llegado este ejemplo. En el próximo post haremos un resumen de lo que se ha visto hasta ahora y publicaré un enlace con el código completo del proyecto para que sirva de ejemplo (o de mal ejemplo :-P).


Saludos desde andorra,


** crossposting desde el blog de Lluís Franco en geeks.ms **

Using Postsharp for solving the inexisting multi-inheritance problem

Well, not really…

As you surely know, you cannot have mutiple inheritance in .NET. That really sucks. Yes, I agree that multiple inheritance might bring several problems but when applied correctly,  it really helps. Don”t believe me? Ok, take a look at WTL.

Back to .NET…Since we can”t use multiple inheritance, we end up defining several interfaces and injecting classes that implement the generic boilerplate code for those interfaces. With Windsor (or any other existing container), we”re able to reduce the necessary code to instantiante an object but we still need to implement all the members of the interfaces that our base class extends. In practice, implementing this methods means redirecting those calls to instance fields that are initiated through injection.

Today I had some free time and I”ve decided to play with Postsharp. One of the things you can do with it is replace this manual tedious work and get all those interfaces implemented automatically during compilation. To achieve this, we need to create a new custom (or should I say, derived) CompositionAspect attribute and apply it the class we want to extend.

Since I really didn”t had much time, I decided to implement something simple and really chose a bad example: the INotifyPropertyChanged interface. I say unfortunately because,as you”ll see,I”ve ended up firing the event from a field change and this made me develop and additional attribute that is used for intercepting field changes (this was necessary due to the way events work). anyway, let”s get started. The first thing we need is a general implementation for the interface. Here”s one good enough for demo code:


public class PropertyChangedGeneralNotification : INotifyPropertyChanged
{
        private readonly Object _firingObject;

        public PropertyChangedGeneralNotification(Object firingObject)
        {
            _firingObject = firingObject;
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if( PropertyChanged != null)
            {
                PropertyChanged(_firingObject, e);
            }
        }
}

This interface defines only one member: an event. My initial idea was to really build a simple class that had only the necessary event. Then, the final injected class would simply fire it. Unfortunately, you cannot do that since you can only “use events like delegates” on the class they”re defined (I”m sure there really is a good reason on why there is such a strong relationship between events and the classes where they are defined, but I still haven”t found a definitive answer for it – btw, if you know, please put it in the comments).

Anyway, that”s why I ended up adding the OnPropertyChanged method and added a constructor which receives a reference to the object that is being injected (we need this because when we fire the event we must pass a reference to that class as the first parameter to the method that handles the event).

Ok, Now we need to build the class that is responsible for injecting the previous generic class. To achieve that, we need to create a new CompositionAspect derived class. This class must be serializable and we can override several methods to control the output of the class to which the attribute is going to be applied. Here”s the code I”ve got:

[Serializable]
public class AOPInterfaceInjectionAttribute : CompositionAspect
{
        public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs)
        {
            return new PropertyChangedGeneralNotification(eventArgs.Instance);
        }

        public override Type GetPublicInterface(Type containerType)
        {
            return typeof (INotifyPropertyChanged);
        }

        public override CompositionAspectOptions GetOptions() {
            return CompositionAspectOptions.GenerateImplementationAccessor;
        }
}

The GetPublicInterface method is responsible for returning the type of the public interface that the injected class will implement. The CreateImplementationObject method must return an object that implements the referenced interface (in this case, we”re returning an instance of the general class we”ve implemented in the previous snippet). Notice that we”re using the InstanceBoundLaosEventArgs to get a reference to the instance that is being injected and passing it to our general class so that the correct reference is passed when the PropertyChanged event is fired.

The final thing you should note is the override of the GetOptions method. We”re saying that in this case we should be able to get a reference to the class that is injected. This means that our “injected” class will also implement the IComposed<T> interface, which has methods that will let us get a reference to that object.

Applying this attribute to an existing class is all that is necessary for exposing the interface:

[AOPFieldChangedInjection]
public class Student
{
        public String Name { get; set; }
        public Int32 Age { get; set; }
}

Now, the only thing that is missing is generating the event. In this case, I though it would be fun to go ahead and create an attribute that intercepts field calls (ok, I know that this is not really the best approach, but at least I can have some more fun and learn more about the platform). When we need to intercept field calls, we can extend the OnFieldAccessAspect class. Here”s what I”ve done:

[Serializable]
public class AOPFieldChangedInjectionAttribute : OnFieldAccessAspect
{
       public override void OnSetValue(FieldAccessEventArgs eventArgs)
       {
           var shouldFireChangedEvent = !eventArgs.ExposedFieldValue.Equals(
                                             eventArgs.StoredFieldValue);
           //call base to change the value of the field
           base.OnSetValue(eventArgs);
           //check if event should be fired
           if (shouldFireChangedEvent)
           {
               InstanceCredentials credentials =
eventArgs.InstanceCredentials;
               var composedInteface = (IComposed<INotifyPropertyChanged>) (eventArgs.Instance);
               var evtHandler = (PropertyChangedGeneralNotification) composedInteface.GetImplementation(credentials);

               if (evtHandler != null)
               {
                   evtHandler.OnPropertyChanged(new PropertyChangedEventArgs(eventArgs.FieldInfo.Name));
               }
           }
       }
}

Overriding the OnSetValue is necessary if you want to intercept a write operation. I start by comparing the old value with the new value that is being saved to the field before callilng the base”s method. The interesting part is the code necessary for firing the event. We start by getting the credentials. This is a nice concept that is used to prevent access from any code to the implementation code; only code that knows the credentials can access the implementation of the interface.

Notice that in this case we end up casting the interface to the class so that we can call the method that ends up generating the event (no, I can”t say that I like the previous code but I can live with it since I”m writing testing exploratory code). As you can see, we end up passing the name of the field instead of passing the name of the property (again, I said that my example was poor, right?)

What matters is that now it”s really easy to reuse our generic code, as you can see from the next class (which should really be in a different assembly from the one that showed the previous code):

[AOPInterfaceInjection]
[AOPFieldChangedInjection]
public class Student
{
        public String Name { get; set; }
        public Int32 Age { get; set; }
}

After compiling, the previous class will implement interfaces INotifyPropertyChanged and IComposed<INotifyPropertyChanged> and you”ll get events fired when you change any of its properties.

There are still lots of stuff you can do with Postsharp. My first impressions are good: with this platform it”s really easy to apply AOP to our projects. I”m still not convinced that this is best thing in thw world, but I”ll keep playing with it and see how it reduces the code that I need to write on my day-to-day scenarios.

Por fin es viernes (30/05/2008)

Como las buenas costumbres no hay que perderlas, he decidido retomar los hilos “por fin es viernes…” que hasta ahora publicaba en mi blog personal, y publicarlos también aquí, en Geeks. Que un poco de humos también va bien de vez en cuando. Gracias a todos los que me mandáis colaboraciones, sin vosotros no habría “PFEV”.

Unos chistes cortos By Cesar:

Restaurante de  lujo:
- ¿Que tomarán los señores….?  
- A mi me pone una langosta Thermidor y un cava  Juve & Camps reserva de familia.
- ¡Excelente decisión!  ¿Y a  su esposa….?
- Póngale un fax y dígale que me lo estoy  pasando de puta madre…..
——————————————————————————–
Dos caballeros que se movían muy  deprisa en el interior de un Hipermercado con sus carritos de compras se  chocan. Uno le dice al otro:
- Perdóneme Usted; es que busco a mi  señora.
- ¡Qué coincidencia, yo también! Estoy ya  desesperado.
- Bueno tal vez le pueda ayudar. ¿Cómo es su  señora?
- Es alta, de pelo castaño claro, piernas bien  torneadas, pechos firmes, un culo precioso, en fin, muy bonita… ¿Y la  suya?.
- Olvídese de la mía, vamos a buscar la  suya…    
——————————————————————————–
Un catalán que esta arrancando el  papel pintado de su casa es visitado por un amigo….
- ¿Qué,  redecorando la casa?.
- No, de mudanza.    
——————————————————————————–
Un tío esta haciendo un crucigrama. 
- Oye, a ver si tu sabes esta: ‘Órgano sexual  femenino’, con cuatro letras, y la segunda es una  ‘O’.
- ¿Horizontal o  vertical?
-  Horizontal.
- ¡Ah! pues entonces ‘boca’.  
——————————————————————————–
Esto es una pareja que se conoce en  una fiesta y la misma noche acaban en la cama. Al acabar, va la chica y dice:
- Oye, tú no tendrás el SIDA,  ¿verdad?
- ¡No!
- Menos mal, ya sería mala suerte cogerlo dos  veces en la misma semana…  
——————————————————————————–
Un hombre dice a su  novia:
- Mari, ahora mismo te la voy a meter hasta el  fondo.
- ¡Joder!, podrías decir algo mas romántico-  dice ella.
- Está bien, Maria, a la luz de la luna te la  voy a meter hasta el fondo.  
——————————————————————————–
- Mamá, mamá ¿cuánto cuesta  casarse?
- No tengo ni idea, hijo; todavía no he acabado  de pagar las consecuencias.  
——————————————————————————–
Un borracho llega a su casa  cantando y haciendo barullo, en eso se asoma un vecino y le dice: 
- ¡¡Psss!!, ¡no haga bulla que su mujer se va a  despertar!
- ¡No se preocupe!, cuando llego así mi mujer y  yo jugamos al exorcista!
- ¿Ah, si? y ¿cómo es  eso?
- Bueno, ella me sermonea y yo vomito!  
——————————————————————————–
Una pareja de ancianos discuten y el le dice a ella:
- Cuando te mueras voy a comprar una losa que  diga: ‘Aquí yace mi mujer, tan fría como  siempre’.
- Y yo voy a poner: ‘Aquí yace mi marido, ¡AL  FIN  RIGIDO!’.
——————————————————————————–
- Mi marido es impotente al 100% 
- Eso no es nada, el mío lo es al  200%
- ¡Pero eso es imposible!. ¿Como puede  ser?
- Es que se ha mordido la lengua esta mañana.  
——————————————————————————–
Una pareja que esta en la cama, son  las 4 de la mañana, los dos muy relajados por haber echado un par de  polvos buenísimos. De pronto él pregunta: 
-¿Quieres que te dé por  culo?.
Ella se para, piensa y dice:
- Bueno, ya que estamos,  ¡adelante!
Y él le  contesta:
- Pues levántate y hazme una tortilla de patatas que estoy muerto de hambre.  
——————————————————————————–
Le dice la madre a la  hija:
- Hija, dicen las vecinas que te estás  acostando con tu novio.
- ¡Ay, mami! la gente es muy chismosa: una se  acuesta con cualquiera y ya dicen que es el novio.  
——————————————————————————–
Dos amigos que se encuentran… 
- Hombre Luis, ¿qué es de tu  vida?
- Pues mira, me he colocado de  funcionario.
- ¡Que bien!, así por las tardes no  trabajas.
- No. Por las tardes no voy. Cuando no trabajo  es por las mañanas.
——————————————————————————–
Un hombre entra en un restaurante y  ve a una mujer muy bonita sola en una mesa. Se aproxima y pregunta: 
- Disculpe señorita, he visto que está usted  sola, ¿puedo sentarme y hacerle  compañía?
La mujer escandalizada, se pone de pie y  responde gritando:
- ¿Usted está loco?, pero ¿qué se piensa que  soy?
Todo el restaurante lo escucha y el hombre sin  saber que cara poner contesta:  
- Disculpe yo sólo quería hacerle  compañía.
A lo que la mujer responde dándole una bofetada  al hombre:
- Y encima insiste!!!!  Atrevido!!
El hombre completamente abochornado se va a la  otra punta del restaurante y decide sentarse allí. A los pocos minutos  la mujer se levanta y se acerca a la mesa de él.  
- Disculpe por la forma que lo traté antes,  pero soy psicóloga y estoy estudiando el comportamiento de las personas  ante situaciones  inusitadas.
El hombre se levanta y contesta  gritando:
- ¿¿100.000 pesetas??? Estás loca!! Ninguna  puta vale eso!!
——————————————————————————–
- Papá, papá.. ¿Por qué os  casasteis tú y mamá?
- Por tu culpa, cabrón!  
——————————————————————————–
En una prueba de alcoholemia el  Guardia Civil le dice al conductor:
- Mire… ¿No le da vergüenza? (Enseñándole el  alcoholímetro que marcaba  3,45)
- ¡Joder!  ¡Las cuatro menos cuarto!   ¡Mi mujer me mata!
——————————————————————————–
- Padre me confieso que el otro día  me acosté con una jovencita de 15 años. 
- Bueno hijo, tampoco es para tanto. Ya lo  dicen las Escrituras: ‘Hay que enseñar al que no sabe’.  
- Sí padre, pero después encontré una señora de  65, que estaba de muy buen ver, y no me negué a su  proposición.
- Jesucristo dijo: ‘Dad de comer al  hambriento’.
- Ya padre, pero lo más grave es que ayer vi a  un moro agachado, con el culito todo redondito, y no me pude reprimir.  
- ¡Vaya hijo! Eso ya es más complicado… ¿Pero  sabes qué te digo? ¡Al que no crea en Dios que le den por culo!!!  
——————————————————————————–
Están un niño y una niña jugando.  El niño le pregunta a la niña:
- ¿Sabes cómo se hacen los niños?  
- No, no lo sé…  
- Pues mira, el papá pone la semillita en la  vagina de la mamá…
- ¿Y luego?  
- Luego la empuja con la polla.  
——————————————————————————–
En un casting para un programa de  televisión se pide a los participantes que den el nombre, los apellidos  y una característica que les haga especiales. 
Llega el primero: ‘Pepe Romerales. 100 m lisos  en 10 segundos’.
El siguiente: ‘Manuel Vargas. Bailarín  profesional’.
En eso llega otro y dice: ‘José Unamuno. Una  polla de 28 cm .’
La que estaba apuntando le mira con los ojos  desorbitados y le pregunta:  
- ¿¿¿Una  qué???
- Unamuno, joder, ¡Como el  escritor!!!


Imágenes de un cementerio chileno (by Carlos):

Imagen1

Imagen2

Imagen3

Imagen4


Fotos curiosas (By Evas):

Imagen1

Imagen2

Imagen3

Imagen4

Imagen5

Imagen6

Imagen7

Imagen8

Imagen9

Imagen11

Imagen12

Imagen13

Imagen14

Imagen15

Imagen17

Imagen18

Imagen19

Imagen20

Imagen23

Buen fin de semana a todos!
:-)


** crossposting desde el blog de Lluís Franco en geeks.ms **

Debian y sus juguetes, Dilbert y los aleatorios

:-)
Esta mañana estaba dándole una ojeada al problema anunciado por Luciano Bello sobre la vulnerabilidad descubierta en OpenSSL, que ha generado claves débiles entre el mes de Septiembre de 2006 y el 31 de Marzo de este año. Cuando de repente me he encontrado con estas tiras del genial Dilbert al respecto de la generación de aleatorios:

debian1

debian2

Y No, no voy a hablar sobre el tema, que ya se ha hablado demasiado… Simplemente hacer la reflexión sobre que pasaría si el fallo de seguridad se hubiese producido en el sistema operativo más maléfico del mundo, creado por Spectra la compañía que pretende dominar el mundo a golpe de Software.

Más info en:
http://metasploit.com/users/hdm/tools/debian-openssl/

Saludos,


** crossposting desde el blog de Lluís Franco en geeks.ms **

F# first impressions

Well, I should really say: first and last impressions! I”ve read about 200-230 pages of the Expert F# book and I think I”ve had enough. Ok, functional languages have really cool concepts like patterns, asynchronous workflows, first class support for functions, etc, BUT…the damn thing is simply unreadable! Just look at this sample:

let rec last l =

   match l with

   | [] -> invalid_arg “last”

   | [h] -> h

   | h::t -> last t

so, be honest: can you really read this and understand what it does? Well, now I can, but I think I”ve seen enough indentations for a lifetime…seeing all these F# snippets just made me want to go back to C++…

On Public Preview

i”ve been waiting with baited breath for the opportunity to talk about the Public Preview of SBS 2008, and it went live yesterday. The SBS Blog carried the announcement from Dean Paron, and you can sign up to download and evaluate the software at the Evaluation Center. If you are going to take a serious look at the software, and by serious, I mean that you are going to run the software through its paces and provide feedback to the development team, make sure that the system you will be testing on meets the minimum system requirements as identified by Microsoft. Running on anything less will not get you the proper experience for the software.


There are a number of changes in SBS 2008 from SBS 2003 and earlier versions. One of the most significant is the change from being able to use the SBS server as an “edge device” by running it with two NICs. SBS 2008 only supports a single NIC (and by single NIC, that means you cannot route private to public traffic through the SBS server – some testers have installed SBS 2008 with two NICs on private networks for physical separation of internal networks) and that”s actually a change in the core Windows Server 2008 operating system, not a design decision by the SBS development team. All deployments of SBS 2008 will be of the “single NIC behind a hardware firewall” vaiety, where the “hardware firewall” could be any number of solutions, including a separate server running ISA. The SBS setup wizards will attempt to configure this external firewall if it”s a hardware device that supports and has enabled UPnP, but the setup wizards will not configure an external ISA server, so ISA integration has been completely removed from this product.


Over the next few days and weeks,I”ll be posting my thoughts and opinions about the product,the successes and failures that I”ve seen in the time I”ve been working with the product. These posts will be focused on significant differences in the product from previous versions so that those who are starting to become familiar with the product can see up front some of the implications of those changes and how that might impact the way you deploy SBS 2008 into an existing environment. While some of these changes may not sit well with the community, if you know about them in advance and can plan for them before implementing the system, you may save yourself some headaches down the road. I liken this to the people who were very familiar with SBS 2000 and made assumptions about SBS 2003 when selling it as a solution to customers without knowing some of the significant changes made at that transition. Specifically, consultants who sold SBS 2003 to b used as a Terminal Serve, like SBS 2000 could do, when Terminal Server support was removed from the product. in this case, you won”t be selling SBS 2008 with ISA – there is no bundled ISA story with SBS 2008, so if you”ve been thinkig about selling SBS 2008 Premium and pitchin ISA as one of the benefits of that sale, you need to make alternate plans NOW.


Hopefully you”ll find the information coming in the next series of posts useful as you begin to think about how SBS 2008 will fit into your product offerings to your customers. Don”t be surprised if you find that, in some cases, SBS 2008 is no longer a fit for customers where SBS 2003 made sense. Times change and tehnology changes, and so has the SBS product. Please make sure that you are familiar with the product and its benefits and limitations before you start deploying it for your customers.

Subclassing Content Query Web Part to override CAML query

The Content Query Web Part (CQWP) in MOSS is one of the popular out-of-the-box Publishing components which is used in content management sites, allowing you to get results from different sources.

But sometimes out of the box functionality is not enough to meet your requirements, and you need to customize CQWP. There are several resources describing how to do this – 1, 2, 3, 4

The most important features which are missed in CQWP are:

  • overriding query to use custom CAML
  • enabling web-part connections

To implement these functionality you need to subclass ContentByQueryWebPart class and override several methods.

Below I will describe what exactly need to be done to achieve desired behaviour.

Query Override

To have custom CAML query in your Web part you need to override CreateChildControls base method. You can find samples how to do this in the references above, but it”s done so implicitly, that you can easily spend hours to find out why you code doesn”t work and gives you different errors

The crucial part is in the way sending the query to the base class within overrided CreateChildControls

   1: protected override void CreateChildControls()
   2: {
   3:     this.QueryOverride = customQueryString;
   4:  
   5:     base.CreateChildControls();
   6:  
   7:     QueryOverride = string.Empty;
   8:  
   9:     CommonViewFields = string.Empty;
  10: }

First, you need to set your custom query to the “this.QueryOverride” to inform base class about query – line 3


Second, call base CreateChildControls() allowing your query being executed – line 5


Third and last – CLEAN query and view fields properties – line 7,9. Without this step you will get errors when open your Web Part in edit mode


Enabling Connection


The Content Query WP doesn”t accept any connections by default. You need to implement this too. Everything you need to to is just add ConnectionConsumer attribute. But trick in setting the right attribute which is used in Parameter dialog box, when you connect two web-parts.


   1: [ConnectionConsumer("Another WebPart", "IFilterValues", AllowsMultipleConnections = true)]
   2: public void SetConnectionInterface(IFilterValues filterProvider)
   3: {
   4:     if (filterProvider != null)
   5:     {
   6:         // save provider with values
   7:         providerValues = filterProvider.ParameterValues;
   8:         _filterProviders.Add(filterProvider);  // variable declaration is List<IFilterValues> _filterProviders = new List<IFilterValues>();
   9:         List<ConsumerParameter> parameters = new List<ConsumerParameter>();
  10:         
  11:         // add params
  12:         parameters.Add(new ConsumerParameter("param1",
  13:                 ConsumerParameterCapabilities.SupportsSingleValue |
  14:                 ConsumerParameterCapabilities.SupportsEmptyValue));
  15:         parameters.Add(new ConsumerParameter("param2",
  16:                 ConsumerParameterCapabilities.SupportsMultipleValues |
  17:                 ConsumerParameterCapabilities.SupportsAllValue |
  18:                 ConsumerParameterCapabilities.SupportsEmptyValue));
  19:  
  20:         filterProvider.SetConsumerParameters(new ReadOnlyCollection<ConsumerParameter>(parameters));
  21:  
  22:         }
  23: }

Method name can be any, but pay attention which provider you are using . WebPart providers send data via different provider interfaces, for example when you are working with Filtering web parts (like “Current User Filter” web part) then you need to “listen” your incoming connections via IFilterValues (thx Mutaz for this findings), for other WB it could be IWebPartField or IWebPartRow.


If you are expecting to get data from WP via unsupported provider you connection link will be dimmed


Practical Sample


@d2design kindly asked to provide practical sample, for example how to use current user as a keyword :)


Actually, it”s good example which shows how use both features I described.


To do this you need to have:


  1. ShareServices (SSP) with UserProfile, where current userName is stored
  2. “Current User Filter” WebPart, to get the userName from SSP. It returns you logged user name by default (not necessary actually, as well as SSP, because you could resolve you user name via standard asp.net User class when construct custom query)
  3. Enable WebPart connections as I described above. You need to use IFilterValue interface for “Current User Filter” and store your incoming user name in variable.
  4. Override query to include your userName in resulted custom query.

 


TIPS:


  1. When you are quering content which is not published and approved (like pages) you wont be able to see that content on the page in final view. You data will be available in page edit mode only, because they are treated as “draft” data.
  2. <OrderBy>CAML tag is not parsed by CQWP, you need to remove it from your query and set the related order field of CQWP class

 


Mirror: Subclassing Content Query Web Part to override CAML query

ASP.NET MVC Preview 3 is out

As always, Scott Guthrie has announced it on his blog (let”s see if I can keep up with all the work the ASP.NET team has been releasing and if I can finally start looking at these new platforms…)

Acceder a la caché de Internet Explorer (III)

RunAs

Impersonation => RunAs

En los dos primeros artículos pudimos ver los objetos del API de Windows que íbamos a usar para poder acceder a la caché de los archivos temporales de Internet, y como persistir estos datos en formato XML.

Hoy vamos a usar Impersonation para ejecutar nuestra aplicación con otras credenciales de usuario, de este modo nos conectaremos a una ubicación remota a la cual sólo tienen permisos para conectarse los administradores.

Supongamos que tenemos una ubicación similar a esta: \RootDFSLogsIECacheQuery y que sólo los usuarios del grupo administradores pueden acceder a leer y modificar su contenido. Si nuestra aplicación se ejecuta con permisos del usuario o servicio local, no podremos guardar los archivos de registro. Sin embargo, en un momento dado nuestra aplicación puede elevar su nivel de privilegios usando las credenciales del administrador, ejecutar las tareas requeridas, y posteriormente volver a su nivel predeterminado para continuar con su ejecución como si tal cosa.

A este proceso se le llama impersonar o suplantar, aunque personalmente no me gusta demasiado la traducción por las posibles connotaciones negativas que conlleva. Y básicamente se trata de que durante un lapso de tiempo nuestra aplicación va a estar ejecutándose con un usuario distinto al usuario que ha iniciado la aplicación.


Artistas invitados: LogonUser y DuplicateToken

La primera de ellas verifica si las credenciales suministradas son correctas, validándolas contra un dominio (que puede ser la estación local) y devuelve un token, mientras que la segunda crea una copia de un token existente. Hay que mencionar un detalle importante y es que el token devuelto por DuplicateToken es lo que se llama un ‘impersonation token‘, que no es válido para la función CreateProcessAsUser ya que ésta necesita un token primario. Si deseamos usar ésta función debemos usar como alternativa la función DuplicateTokenEx.

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
 
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
 

 

Más información aquí:

 

LogonUser Function:


DuplicateToken Function:
http://msdn.microsoft.com/en-us/library/aa446616(VS.85).aspx


Bien, ahora que ya nos conocemos todos vamos a ver un fragmento del código de la aplicación, que usa estas funciones para impersonar un usuario y devolver un objeto de tipo WindowsImpersonationContext. Posteriormente podremos usar el método ‘Undo’ de este objeto para deshacer el contexto de suplantación y volver al contexto anterior, de forma que la aplicación seguirá ejecutándose con el usuario que la ha lanzado.


public WindowsImpersonationContext ImpersonateUser(
    string sUsername, string sDomain, string sPassword)
{
    IntPtr pExistingTokenHandle = new IntPtr(0);
    IntPtr pDuplicateTokenHandle = new IntPtr(0);
    pExistingTokenHandle = IntPtr.Zero;
    pDuplicateTokenHandle = IntPtr.Zero;
 
    if (sDomain == "") sDomain = System.Environment.MachineName;
    try
    {
        string sResult = null;
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, 
            ref pExistingTokenHandle);
 
        if (false == bImpersonated)
        {
            int nErrorCode = Marshal.GetLastWin32Error();
            sResult = "LogonUser() failed with error code: " + nErrorCode + "rn";
            throw new Exception(sResult);
        }
 
        sResult += "Before impersonation: " + WindowsIdentity.GetCurrent().Name + "rn";
        bool bRetVal = DuplicateToken(pExistingTokenHandle,
            (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, 
            ref pDuplicateTokenHandle);
 
        if (false == bRetVal)
        {
            int nErrorCode = Marshal.GetLastWin32Error();
            CloseHandle(pExistingTokenHandle);
            sResult += "DuplicateToken() failed with error code: " + nErrorCode + "rn";
            throw new Exception(sResult);
            return null;
        }
        else
        {
            WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
            WindowsImpersonationContext impersonatedUser = newId.Impersonate();
            sResult += "After impersonation: " + 
                WindowsIdentity.GetCurrent().Name + "rn";
            this.ImpersonationContext = impersonatedUser;
            return impersonatedUser;
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        if (pExistingTokenHandle != IntPtr.Zero)
            CloseHandle(pExistingTokenHandle);
        if (pDuplicateTokenHandle != IntPtr.Zero)
            CloseHandle(pDuplicateTokenHandle);
    }
}






Vaya, esto es Impersionante…


Cabe destacar que en la llamada a LogonUser, se pasa un puntero al token de usuario ‘pExistingTokenHandle’ que posteriormente se usa en la llamada a DuplicateToken. Ésta devuelve el duplicado mediante ‘pDuplicateTokenHandle’, que posteriormente es usado para crear una nueva identidad y llamar a su método Impersonate, que es realmente la que se encarga de realizar la suplantación con el nuevo token.


(*) El siguiente código no funcionará en plataformas Windows 98 o Windows Me, ya que no poseen la posibilidad de trabajar con tokens de usuarios.


Una vez realizado el trabajo que requería de la suplantación de identidad, para volver al contexto predeterminado basta con invocar al método Undo del objeto WindowsImpersonationContext del siguiente modo:


Security.SecurityContext sec = new Security.SecurityContext();
 
if (Properties.Settings.Default.SaveResultsUsingImpersonation)
{
    sec.ImpersonateUser(
        Properties.Settings.Default.ImpersonateUser,
        Properties.Settings.Default.ImpersonateDomain,
        Properties.Settings.Default.ImpersonatePwd);
    appEventLog.WriteEntry(
        string.Format("Begin Impersonation, Current user as {0}",
        WindowsIdentity.GetCurrent().Name));
}
//
//Realizar acciones que requieren suplantación..
//
if (Properties.Settings.Default.SaveResultsUsingImpersonation)
{
    sec.ImpersonationContext.Undo();
    appEventLog.WriteEntry(
        string.Format("End Impersonation, Current user as {0}",
        WindowsIdentity.GetCurrent().Name));
}

Conclusión


Espero que este post haya clarificado cómo realizar este proceso. En el siguiente veremos cómo encapsular toda la aplicación para ejecutarse en forma de servicio. Ah! y antes que me lo diga alguno, ya se que no sería el mejor ejemplo para mostrar un servicio de Windows (porque corriendo con permisos de LOCALSYSTEM no se tiene permiso a la caché del usuario), pero tenía un post al respecto pendiente desde hace tiempo. Así que lo juntaremos todo en un mix o refrito o como queráis llamarlo, para que sirva de ejemplo.


También al final de la serie, postearé un recopilatorio de los pasos que hemos seguido y el código completo del ejemplo, por si alguien está tan loco como para querer probarlo :-P


Ahora, a impersonar todos. Pero si lo hacéis, por favor hacerlo bien… no de este modo:


blas


Saludos desde Andorra


** crossposting desde el blog de Lluís Franco en geeks.ms **

Recent Comments