Results for category "Microsoft"

10 Articles

Unity 2.0 in eine ASP.NET MVC 2 Umgebung integrieren

Für ein aktuelles Projekt entwickeln wir mit .NET Framework 3.5 und ASP.NET MVC 2. Um von der fest-codierten Instanzierung von Objekten Abstand zu nehmen (u.a. für das Mocking) und die Applikation frei konfigurierbar zu machen, habe ich mir mal Unity 2.0 angeschaut. Leider beziehen sich die meisten Tutorials und Blog-Posts zu Unity auf eine andere Version, deshalb folgt hier ein kleines Beispiel.

Zuerst einmal müssen die DLLs von Unity dem Projekt hinzugefügt werden. Dann erstellen wir unser DAL:

namespace Test.Dal
{
    public class Benutzer
    {
    }

    public class BenutzerDal : IBenutzerDal
    {
        public IEnumeration<Benutzer> FindAll()
        {
            List<Benutzer> r = new List<Benutzer>();
            r.add(new Benutzer());
            return r;
        }
    }

    public interface IBenutzerDal
    {
        IEnumeration<Benutzer> FindAll();
    }
}

Natürlich haben wir – wie es sich für eine Web-Anwendung gehört, auch den passenden Controller, der folgendermaßen aufgebaut ist:

namespace Test.Controller
{
    public class BenutzerController : Controller
    {
        private IBenutzerDal benutzerDal;

        public BenutzerController(IBenutzerDal benutzerDal)
        {
            this.benutzerDal = benutzerDal;
        }

        public ActionResult Index()
        {
            return View(benutzerDal.FindAll());
        }
    }
}

Auf die passende View habe ich mal verzichtet, da dies selbsterklärend sein sollte.

Standardmäßig werden alle Controller von ASP.NET automatisch erstellt. Damit nun Unity die Factory-Methode für die Controller übernimmt, müssen wir in der Global.asax.cs eine neue Controller-Factory schreiben:

namespace Test
{
    public class MvcApplication : System.Web.HttpApplication
    {
        // Konstante, um später darauf zugreifen zu können
        public const string UNITY_CONTAINER = "unityContainer";

        protected void Application_Start()
        {
            // RegisterRoutes(RouteTable.Routes); u.s.w.

            // Container erstellen
            var container = new UnityContainer();
            // Sektion "unity" aus der Web.config laden
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            // XML-Sektion in den Container laden
            container.LoadConfiguration(section);
            // Neue Controller-Factory erzeugen
            var controllerFactory = new UnityControllerFactory(container);
            // Standard ControllerFactory durch unsere eigene ersetzen
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
            // Den Unity-Container in der gesamten Applikation verfügbar machen
            Application[UNITY_CONTAINER] = container;
        }

    public class UnityControllerFactory : DefaultControllerFactory
    {
        private readonly IUnityContainer container;

        public UnityControllerFactory(IUnityContainer container)
        {
            this.container = container;
        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            IController r = container.Resolve(controllerType) as IController;
            return r;
        }
    }
}

Mit diesem Code wird die Standard-ControllerFactory durch unsere eigene Implementierung ersetzt, die wiederum an den ApplicationContext Unity-Container delegiert.

Den Container selbst habe ich noch einmal global in der Applikation verfügbar gemacht, so dass wir darauf auch bei Filterklassen zurückgreifen können.
Vorstellbar wäre, dass bei jedem Request die aktuellen Rechte des Benutzers in der Datenbank überprüft werden sollen (ja, geht auch mit AuthorizationAttribute…). Unser Filter schaut folgendermaßen aus:

namespace Test.Filter
{
    public class MyFilter : IHttpModule
    {
        private HttpApplication httpApplication;

        private UnityContainer unityContainer;

        private IBenutzerDal benutzerDal;

        public void Init(HttpApplication httpApplication)
        {
            this.httpApplication = httpApplication;
            // globalen Container aus der Applikation ziehen
            unityContainer = (UnityContainer)this.httpApplication.Application[MvcApplication.UNITY_CONTAINER];
            // Unity anweisen, dass eine Instanz der Klasse geladen werden soll, die IBenutzerDal implementiert
            benutzerDal = unityContainer.Resolve<IBenutzerDal>();
            // Handler zuweisen... etc.
        }
    }
}

Mit diesem Code sorgen wir für die Verfügbarkeit des Unity-Containers innerhalb eigener Filter.

Letztendlich fehlen noch die Einträge in der web.xml bzw. dispachter-servlet.xml Web.config:

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias alias="IBenutzerDal" type="Test.Dal.IBenutzerDal, Test" />
    <alias alias="BenutzerController" type="Test.Controller.BenutzerController, Test" />
    <container>
      <register type="IBenutzerDal" mapTo="Test.Dal.BenutzerDal, Test "/>
      <register type="BenutzerController" />
    </container>
 </unity>
 <system.web>
 <!-- ... -->
 <httpModules>
 <!-- andere Module ... und dann unser Filter -->
 <add name="meinFilter" type="Test.Filter.MyFilter, Test"/>
 </httpModules>
 </system.web>
</configuration>

Über das Tag alias lassen sich für Klassen oder Interfaces Aliase definieren, so dass man diese nicht immer wieder vollständig anzugeben braucht. Das Attribut type legt fest, welche Klasse/welches Interface (Test.Dal.IBenutzerDal) in welchem Namespace (Test) hinter dem Alias steckt.
Im Abschnitt container wird nun jede Klasse eingetragen, die in der Applikation verfügbar sein soll. In der ersten Zeile wird ein Typ mit dem Interface Test.Dal.IBenutzerDal registriert, hinter dem sich die Konkrete Klasse (mapTo) Test.Dal.BenutzerDal versteckt. In der zweiten Zeile wird ein Typ Test.Controller.BenutzerController registriert, hinter  dem sich eine Instanz von Test.Controller.BenutzerController versteckt.

Unity überprüft bei jeder Initalisierung (d.h. Erzeugung der Objekte), welche Argumente der Konstruktor des Typs entgegen nimmt und löst diese anhand der bereits registrierten Typen auf. Aus diesem Grund brauche ich beim BenutzerController auch nicht das IBenutzerDal als Konstruktor-Parameter übergeben.
Weiterhin werden alle Objekte standardmäßig als Singleton registriert. Das Verhalten lässt sich aber ändern.

Mehr zu Unity gibt es in der Dokumentation, besonders empfehlenswert ist die Erklärung zum XML-Schema von Microsoft, wo dann u.a. auch Elemente wie property zum Injizieren von Eigenschaften nach Objekterzeugung besprochen werden.

Visual Studio 2008: "Der Projekttyp wird von dieser Installation nicht unterstützt"

Für ein aktuelles Projekt wollte ich gestern mal wieder Visual Studio 2008 benutzen, da ich in C# eine Funktionalität implementieren musste.
Ich startete also Visual Studio öffnete die Projektmappe und bekam den Fehler “Der Projekttyp wird von dieser Installation nicht unterstützt”.  Das Projekt nutzte das ASP.NET MVC -Framework und so vermutete ich, dass es irgendwelche Probleme mit einem bereits installierten Visual Studio 2010 Express inkl. ASP.NET MVC 3 gab.

Der Fehler trat nach der Deinstallation von ASP.NET MVC 3 und erneuter Installation von ASP.NET MVC 2 immer noch auch. Glücklicherweise schaute ich in die Ereigniszeige und fand im Protokoll Anwendung unter anderem folgenden Fehler:

Fehler in Vorlage (“c:Program FilesMicrosoft Visual Studio 9.0Common7IDEItemTemplatesVisualBasicWebMVC 2MvcViewUserControlItemTemplatev2.0.vb.zip”), Datei (“MvcViewUserControlItemTemplate.vb.vstemplate”). Nicht registrierter Projekttyp (“VisualBasic”). Die Ursache hierfür kann ein falscher Projekttyp sein, oder das Projekttyppaket ist nicht installiert.

Die anderen auftretenden Fehler hatten mehr oder weniger den selben Inhalt: Der Projekttyp VisualBasic sei nicht registriert – was auch vollkommen richtig gewesen ist, da ich Visual Basic nicht installiert hatte. Wer braucht schon Visual Basic…

Die Lösung für das Problem war dann an sich ganz einfach: Kurz die Installation vom Visual Studio 2008 ändern, Visual Basic nachinstallieren und schon konnte ich das Projekt öffnen.

Additional property page sheet in Active Directory User and Computer MMC

Some time ago I developed ADUaCET, an extension for the Active Directory User and Computer MMC snap-in. Sad to say but the ADUaCET property page is not shown if you are searching for an user. It is only available if you use the procedure right click $USER -> Properties. I struggled the whole day with collecting information about this issue.

My results are the following:

  • It is not possible to use .NET and only Microsoft.Management.Advanced.PropertySheetExtension for having the property page tab after doing an Active Directory search.
  • Active Directory User and Computer MMC delegates the search to dsquery.dll, OpenQueryWindow. OpenQueryWindow uses an out pointer to pass back the Active Directory entries which were found by search query.
  • All default property pages (Member of, Sessions, Organization etc.) are included by MMC as COM objects.
  • All COM objects to be included in the User property page are stored in the Active Directory schema in CN=adminPropertyPages,CN=user-Display,CN=40[7|9],CN=DisplaySpecifiers,CN=Configuration,DC=yourdomain,DC=local. You can use ADSIEdit to change the used COM objects.
  • adminPropertyPages contains 10 GUIDs by default which are references to the registered COM objects. For example %systemroot%system32adprop.dll (GUID {6DFE6488-A212-11D0-BCD5-00C04FD8D5B6}) is one of them.
  • For determining which COM DLLs are used take an entry from adminPropertyPages and search your registry below HKLMSOFTWAREClassesCLSID$GUIDInProcServer32
  • A good example for registrating a new property page sheet COM object can be found at Yusufs.Directory.Blog (German).
  • Microsoft has two pages about Implement the Property Page COM Object and Registering the Property Page COM Object
  • codeproject.com has an example project which is based on .NET/C#. The example publishes a new property page sheet as COM object. Really helpful!

.NET aus der Sicht eines Java-Entwicklers

Die letzten beiden Tage war ich damit beschäftigt, ein paar Evaluierungen für die .NET-Plattform zu machen. Eines unserer Projekte greift mit Hilfe eines (zugegebenermaßen ziemlich coolen) WPF-Frontends über WCF auf einen SOAP-Service zu, der die Verbindung zu einer MS SQL-Datenbank herstellt.

Logging auf die Konsole

Unter Java bzw. innerhalb eines Application-Servers ist es kein Problem, ein simples System.out.println() oder eben log.debug() zu benutzen. Die Ausgaben erscheinen dann jeweils in der Konsole der Entwicklungsumgebung. Wer jetzt denkt: so etwas geht doch sicherlich auch mit ASP.NET, der irrt gewaltig. Wenn innerhalb einer ASP.NET-Anwendung – hier zähle ich unseren WCF-Service einfach mal dazu – auf die Konsole geloggt wird (per log4nets Log.Debug oder aber Console.Write()), verschwinden die Ausgaben im Nirvana. Grund dafür ist, dass der IIS keine Konsole zur Verfügung stellt, in die überhaupt geloggt werden kann.

Entweder man benutzt nun die Trace-Methoden oder aber man schreibt die Logging-Ausgaben von log4net in eine Datei und setzt auf diese dann ein tail ab.

Lebenszyklus eines WCF-Service

Als JEE-Entwickler weiß ich, dass ein Servlet mit dem Start der Anwendung einmalig initalisiert wird und das Servlet dann so lange im Arbeitsspeicher gehalten wird, bis die Applikation heruntergefahren wird.

Bei WCF wird das Attribut InstanceContextMode benutzt, um die Gültigkeit eines Objekts zu beschreiben. Für einen WCF-Service gilt die Standardeinstellung, dass das Objekt (der Service) so lange vorgehalten wird, bis die gegenwärtige Session beendet wird (Einstellung PerSession).

Reihenfolge der Initalisierung von Servlets / Initialkonfiguration

In Anwendungen, die ich nicht mit Spring geschrieben habe, habe ich in meiner web.xml immer ein Servlet definiert, dass nichts weiter macht, als das die Standardeinstellungen gesetzt und z.B. der Logger initalisiert wird.

Bei .NET gibt es so etwas in der Art nicht (sollte ich falsch liegen, bitte ich um baldige Korrektur). Stattdessen muss man über eine selbst definierte ServiceHostFactory diese Konfiguration durchführen. Möglich wäre so etwas:

namespace My.Namespace.Service
{
    public class CustomServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
    {
        private Boolean isInitialized = false;

        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            initalize();
            return base.CreateServiceHost(constructorString, baseAddresses);
        }

        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            initalize();
            return base.CreateServiceHost(serviceType, baseAddresses);
        }

        private void initalize()
        {
            if (isInitialized)
            {
                return;
            }

            log4net.Config.BasicConfigurator.Configure();
           // Weitere Initialisierungen
        }
    }
}

In der jeweiligen .svc-Datei muss dann die Instanzierung des Service über die CustomServiceHostFactory geschehen:

<%@ ServiceHost Language="C#" Debug="true" Factory="My.Namespace.Service.CustomServiceHostFactory" Service="My.Namespace.Service" CodeBehind="Service.svc.cs" %>

Service-Verbindungen im Client

Hinten über bin ich gefallen, als ich in der app.config des Clients probierte, das Suffix des Service-Endpoints einmalig über

<add key="httpBaseAddress" value="http://localhost" />

zu definieren. Das Attribut httpBaseAddress ist nur auf der Serverseite verfügbar und führt dazu, dass Redundanzen durch doppelte URIs entstehen.
Korrekt schaut das Beispiel nun so aus:

<configuration>
    <appSettings>
    </appSettings>
    <system.serviceModel>
      <!-- CusomtBinding benutzen, da mit wsHttpBinding NTLM nicht korrekt funktioniert -->
        <bindings>
          <customBinding>
            <binding name="Binding_Service">
              <mtomMessageEncoding />
              <security authenticationMode="SecureConversation">
                <secureConversationBootstrap authenticationMode="SspiNegotiated" />
              </security>
              <httpTransport authenticationScheme="Ntlm"/>
            </binding>
          </customBinding>
        </bindings>
        <client>
          <endpoint address="http://localhost:52264/Service.svc"
              binding="customBinding" bindingConfiguration="Binding_Service"
              contract="My.Namespace.Service.IService" name="Binding_IService">
            <identity>
              <dns value="localhost" />
            </identity>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Im Client wird dann über

ChannelFactory ServiceFactory = new ChannelFactory("Binding_IService");

der Proxy des Services geladen.

Die obige Konfiguration (customBinding) zeigt übrigens den Zugriff auf den Web-Service via NTLM. Mit dem Binding wsHttpBinding funktioniert NTLM nämlich nicht.

Microsoft Outlook & RSS: "Der RSS-Inhalt kann von Outlook nicht über 'https://…' verarbeitet werden. Der Hyperlink zeigt möglicherweise nicht auf eine gültige RSS-Quelle."

Unser Build-Server stellt einen RSS-Feed mit den letzten Subversion-Commits bereit. Nach einer internen Umstellung der Einstellungen ist der Feed dabei nicht mehr über HTTP sondern über HTTPS zu erreichen.
Wenn man nun versucht, diesen Feed in den internen Feed-Reader von Outlook aufzunehmen, erscheint die Fehlermeldung Der RSS-Inhalt kann von Outlook nicht über ‘https://…’ verarbeitet werden. Der Hyperlink zeigt möglicherweise nicht auf eine gültige RSS-Quelle..

Die Fehlermeldung deutet nicht an, was denn an dem RSS-Feed nicht stimmt. Ich wusste allerdings, dass der RSS-Feed vollkommen in Ordnung ist und das der Feed über HTTP richtig geladen wurde. Deshalb vermutete ich, dass mit dem selbst-signierten Zertifikat des Webservers etwas nicht stimmte.
Damit nun Outlook den Feed annimmt, muss das Zertifkat der Website im Zertifikate-Speicher installiert werden. Dazu hier das Vorgehen.

  • Im Internet Explorer die URL des Feeds aufrufen
  • Oben rechts in der URL-Leiste auf das rote Schild-Symbol klicken und Zertifikat anzeigen lassen
  • Im nun erscheinenden Zertifkat-Fenster im Tab Allgemein auf Zertfikat installieren klicken
  • Im Zertifikatsimport-Assistent auf Weiter, Weiter, Fertig stellen und Ja klicken
  • Outlook neu starten
  • RSS-Feed nochmal hinzufügen und glücklich sein

Update Unter Windows 7 kann je nach Active Directory-Einstellungen und Berechtigungen dieses Vorgehen nicht funktionieren, da der Button Zertifikat installieren im Internet Explorer deaktiviert ist. Das Zertifikat muss daher lokal gespeichert werden, z.B. als .DER-Datei.
Nach einem Doppelklick auf Datei erscheint der Button Zertifikat installieren. Das Zertifikat muss dann bei der Zertifikatespeicher-Auswahl unter “Vertrauenswürdige Stammzertfizierungsstellen” o.ä. installiert werden.

Gelöst: Encoding-Probleme mit MS SQL und PHP

Seit letzter Woche habe ich mich mit einem äußerst ominösen Problem beschäftigt – wär ja sonst auch langweilig: Ich habe für einen Kunden ein Import-Script geschrieben, dass aus mehreren Text-Dateien die Daten in eine MS SQL Server 2005-Datenbank importiert.
Bei unseren Tests hier in der Firma funktionierte alles wunderbar, es gab keine UTF-8- oder sonstigen Zeichensatz-Probleme – die Umlaute wurden korrekt dargestellt.

Nun meldete sich der Kunde und teilte uns mit, dass die Umlaute falsch dargestellt wären. Aus einem “für” wurde ein “fnr” u.s.w. Ein Schelm, wer jetzt denkt, es würde an UTF-8 liegen. Daran lag es nämlich nicht.

Der Kunde setzte einen amerikanischen Windows Server 2003 und ebenfalls einen amerikanischen Microsoft SQL Server 2005 ein – wir hingegen hatten die jeweils deutschen Versionen eingesetzt. Lag es an den unterschiedlichen Länder-Einstellungen? Nein, daran lag es nicht – wie wir nach dem Aufsetzen der gleichen Maschine feststellten.

UTF-8-Probleme auf Seiten PHP konnte ich ebenfalls ausschließen, da sonst substr() aus dem “für” ein “fn” hätte machen sollen.

Über die Lösung des Problems bin ich mehr durch Zufall gestolpert: Das Tool cliconfig.exe (zu finden unter %WINDOWS%system32) bietet unter dem Tab DB-Library Options die Option Automatic ANSI to OEM conversion. Auf unseren System war diese Option deaktiviert, beim Kunden hingegen aktiviert. Warum? Ganz einfach: die Datenbank beim Kunden lief vor einigen Monaten noch unter MS SQL Server 2000 und wurde dann auf SQL Server 2005 geupgradet. Die Standard-Einstellungen für o.g. hatten sich vom Versions-Wechsel anscheinend geändert und somit konnten wir eben nicht die exakt gleichen Bedingungen nachstellen.

Was für ein Gefrickel, aber: Wieder ein Problem weniger auf der Welt.

Update: Ganz wichtig in diesem Zusammenhang ist, dass das Umlautproblem nur auftritt, wenn das PHP-Script von der Kommandozeile aufgerufen wird. Der Aufruf des Scripts als ausgeführtes CGI-Script in einer Apache-/IIS-/…-Umgebung liefert die richtigen Resultate.

Sharepoint mit Apache als Reverse Proxy veröffentlichen

Heute stand ich vor der Aufgabe, dass unsere interne Sharepoint-Seite im Apache veröffentlicht werden sollte. An sich hätte das kein Problem sein sollen – war es im Endeffekt aber.

Bei uns schaut es schematisch so aus, dass der Apache alle Anfragen anhand des Domain-Namens auf die virtuellen Server weiterreicht bzw. als Proxy fungiert: Internet -> Apache / DMZ -> Virtueller Host / Backend Server.

Anhand des Blog-Eintrags von Todd Klint den Sharepoint-Service so eingerichtet, dass er auf die richtige URL lauscht. Die Konfigurationsdatei des virtuellen Hosts sah dann folgendermaßen aus:

<VirtualHost *:443>
SSLEngine On
SSLProxyEngine On
SSLCertificateFile "$CERT_FILE"
SSLCertificateKeyFile "$CERT_KEY_FILE"
SSLProxyCACertificateFile "$CERT_CA_FILE"
ProxyRequests Off
ProxyVia On

ServerAdmin admin@sps.mydomain.com
DocumentRoot $VHOST_DIR/sps/web
ServerName sps.mydomain.com:443
ErrorLog "|rotatelogs.exe $VHOST_DIR/sps/logs/%Y%m%d_ssl_error.log 86400"
CustomLog "|rotatelogs.exe $VHOST_DIR/sps/logs/%Y%m%d_ssl_access.log 86400" common

# AddDefaultCharset ISO
LogLevel debug
ProxyPreserveHost Off
KeepAlive Off

ProxyPass /  http://backend-srv:8080/
ProxyPassReverse /  http://backend-srv:8080/

<Proxy *>
Order allow,deny
Allow from all
</Proxy>

<Directory "$VHOST_DIR/sps/">
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

Es ist noch zu sagen, dass der Sharepoint nicht mit HTTPS sondern mit Plain-HTTP läuft. Der Apache kümmert sich um die Verschlüsselung. Im IIS muss außerdem als Authentifizierungsmethode für die Sharepoint-Seite Standardauthentifizerung und nicht Integrierte Windows-Authentfizierung benutzt werden. Apache 2.0.63 kam bei mir mit der Benutzung von NTLM nicht klar.

Ein weiterer Fehler der auftrat war, dass der Sharepoint-Server über zwei Netzwerkkarten verfügte, die zu veröffentlichende SharePoint-Instanz aber an keine IP fest gebunden gewesen ist. Der Apache hatte Probleme damit arge Probleme (sporadisches “Verbindung fehlgeschlagen”), deshalb habe ich die SP-Instanz einer IP direkt im IIS zugewiesen.

Rautiges 2009-05-26

  • Samstag ging es spannend in Wolfsburg zu. Den Mittag über verfolgte ich auf n-tv die Wahl zum Bundespräsidenten. Interessanterweise erfuhr ich heute, dass Lammerts Verhalten nach bzw. während der Wahl für ein Nachspiel sorgt.
    Nach der Wahl lernte ich Mathe weiter und machte mich gegen 15 Uhr auf in die Wolfsburger Innenstadt. Was da los war, war echt unglaublich. Und gegen 17.15 Uhr wurde der Traum eines jeden Wolfsburger Fußball-Fan wahr: Vfl wurde deutscher Meister. Die Stimmung war natürlich fantastisch, ich machte mich aber wieder auf den Weg zurück zur Wohnung.
    Zu später Stunde holte ich dann einen volltrunkenen Timo von der Bushaltestelle ab und fuhr ihn noch zu Lippe.
  • Das Modul “Mathematisch-logische Grundlagen” geht in die heiße Phase. Die meisten Aufgaben – bis auf 3 – habe ich eingereicht und sind soweit in Ordnung. Seit Donnerstag sitze ich an der Zusammenfassung aller Kapitel. Großer Vorteil: Beim zweiten Mal lesen verstehe ich die Texte wesentlich besser 🙂
    Nächstes Wochenende folgt dann Abschlusstest und Online-Klausur, damit ich am 19. Juni meine Klausur in Witten schreiben kann.
    Das nächste Modul wird wohl Web-Design werden und zusätzlich nebenbei noch Mathe 1. Mit M1 werde ich mir aber keinen Stress machen, so wie ich das bei MLG gemacht habe.
  • Florian ist momentan dabei, eine eigene kleine Ubuntu-basierende Distribution zusammenzustellen. Diese lädt nach dem Start EFA, Elektronisches Fahrtenbuch – ein Tool für Rudervereine, und sichert automatisch die EFA-Datenbank auf hot-plugged USB-Sticks. Dabei kam dann heraus, dass VirtualBox und VMWare massive Probleme beim Durchreichen von USB-Geräten haben. Ubuntu 8.10 bzw. der Kernel der 8.10er verliert nach einigen Sekunden die Verbindung zu den USB-Geräten.
    Sobald das Projekt abgeschlossen ist, wird Florian hoffentlich die Anleitung dazu auf seinem Blog veröffentlichen.
  • Nur damit ich es nicht vergesse: Auf SlickTools gibt es zwei .NET CF 2.0 Anwendungen. Eine ist ein mobiles Metronom, die andere eine Stoppuhr. Beides werde ich bei den nächsten Bandproben mal einsetzen.
  • Auch für nächsten Monat sind einige kleine Anschaffungen geplant:
    • Steckdosenleiste mit Überspannungsschutz für Server, Router und Kabelmodem. Ich trau’ dem Blitzableiter im Haus nicht.
    • Roland Micro Cube für das Üben in der Wohnung. Hab kein Nerv, immer mein MG 30 DFX mit nach oben zu schleppen. Und ohne Verstärker E-Gitarre zocken ist langweilig.
    • Eventuell ein Mikrofonständer. Da bin ich aber noch am Überlegen, ob ich so etwas wirklich brauche. Im Proberaum haben wir die Ständer.
    • Neues Server-Board. Da drücke ich mich noch vor. Bin am Überlegen, ob ich mir nicht doch ein Ion hole oder eines von den neuen Intel Embedded-Boards.
  • Bandmäßig schaut es so aus, dass Dennis nun als Bassist(in) mit an Bord ist. Am Vatertag haben Jan und ich ein kleines Akustik-Gitarren-Konzert gegeben, was meiner Meinung nach ganz okay war.

In aller Kürze: Unter Linux WAV zu MP3s konvertieren

Nach der gestrigen Bandprobe bekam ich unsere Samples als WAV zugeschickt. Als ich mit lame versuchte, die Dateien mit lame in.wav out.mp3 zu konvertieren, bekam ich den Fehler Unsupported data format: 0x0011. Der Fehler enstand dadurch, dass die WAV-Datei mit einer Kamera aufgenommen wurde. Die Kamera wandelt den Audio-Stream automatisch nach Microsoft ADPCM und nicht pures PCM um. Außerdem wird eine Sample Rate von 8000 Hz benutzt. Ungünstig.

Mit ADPCM kommt hingegen ffmpeg klar. Leider ist aus lizenzrechtlichen Gründen in den Binaries von Ubuntu der MP3-Outputstream nicht mit kompiliert wurden. Deshalb braucht man einen zusätzlichen Konverter, wie z.B. Bladeenc.

Damit nun alles funktioniert und Bladeenc nicht den Fehler ERROR: Sample ‘sample.wav’ is not in 32, 44.1 or 48 kHz!
meldet, muss folgendermaßen vorgegangen werden:

ffmpeg -y -i sample_low.wav -ar 44100 sample_high.wav
bladeenc sample_high.wav sample.mp3

Microsoft Tag – 2D Barcode – Protokollanalyse und Sicherheit

Marc berichtete gestern über Microsoft Tag. Tag ist ein 2D-Barcode, der mittels 4 verschiedenen Farben und deren Kombinationen einen Hash bildet.
Mit der Kamera des Handys wird der Tag aufgenommen und dann an einen Microsoft-Server geschickt. Dieser überprüft, ob der Hash registriert ist und liefert an den Client zurück, ob dieser Hash existiert. Hinter einem Hash kann sich ein Link, ein Freitext, eine Telefonnummer oder eine vCard verbergen.
Wenn der Hash existiert, werden eben diese Informationen zurückgesendet. Das Prinzip ist also ganz simpel.
Mir stellte sich nun die Frage, wohin gehen denn überhaupt die Daten und was wird an den Client gesendet?

Zur Überprüfung schloss ich mein HTC Touch Diamond mittels USB-Kabel an den PC an, startete Wireshark und schaute mir die Verbindungen an.
Sobald das Handy eine Anfrage an den Server stellt, wird an rs.tag.microsoft.com über TCP/80 (normales HTTP) ein GET-Request gesendet. Der GET-Request sieht folgendermaßen aus

GET /6FADWESYVPYSPHHQ5TMKHGSWF3ODWWRP.aspx?Level=1&amp;amp;amp;amp;amp;amp;VID=1%2B71&amp;amp;amp;amp;amp;amp;TH=_%2BxrkrK8F013hNEWheA%24&amp;amp;amp;amp;amp;amp;PL=zqMa3C48QBs_4fI9cRZKGpvix1XhvxuqEQ1eFlqKqwlbXzl%2BgvWxM7zTaq0xRFcdWuneeC5VRGuYitVRubwb1kswVAc19dpoJDZEf5HpqlbHvw7WPzpVYibwvX02LygEnOXbXbTbeM04VzICWva2GVdYXXKekdxPvL8evEZbJG5Xi8t9PUlVHOL_yS_dsXi2XT5cejeRsGArLzVpkvjcPLyyG6csBzoOTeHuKiZLTnKYgLcyxqMQvDQtIQ5J6rYFW19SZ4r1

rs.tag.microsoft.com liefert danach dann

<PAYLOAD><NAME>Deine</NAME><PIN>0</PIN><DATA>r6QEsUVaVGZOm9MVWDszHo_0vTzeonHOUytWESKQ3gVLLjl5kfK5IsvFGaJYLDsDGqrrMzErE1C3rNcrtKwYrE1J</DATA></PAYLOAD>

zurück.

Um etwas strukturierter an die Sache zu gehen, hier die Tests mit den einzelnen Typen.

Dialer

Request:

GET /7KDWMBOYE474DQA7PMH5KVDLDK4SGSZJ.aspx?Level=1&VID=1%2B71&TH=_%2BxrkrK8F01ahPoWheA%24&PL=tr8e2zMtRBU68uguaBwhGIz43Bv8ujayaxlTASP4zA8jQz15n%2BS1PbnAcL4oTjwfTfPFZDNOQ3PinthGwM580DMsUAAo5N5mISVebIjjwVTQpRXKIiFSelzksGpPXU8C5PnfWqnKfMM9RCgRQ_zdG0BCRm6DittXxqsTqz8pQ2gvl896IFhREufs0zzEuxO0SiRHZiqKt3hROzh%2B64q7OsSuH6AxFj4ASPL0OT9BJXCPmqwu27gXpE45LBkwmNEDI0NWYJfk

Response:

<PAYLOAD><NAME>Dialer</NAME><PIN>0</PIN><DATA>r6QEsUVaVGZOm9MVWDszHo_0vTzKymK1QjZaFzWG3RpKMy9onPusWcm3GKpCPVd5TvK9biFaSXqGgLRSycY$</DATA></PAYLOAD>

vCard (ohne Passwort)

Request:

GET /DYMDUQZA5HDH3KXOEV7X5DPS7S4U2ZSN.aspx?Level=1&VID=1%2B71&TH=_%2BxrkrK8FE1lhPwWheA%24&PL=utsO1EIiWgwg8OM9CRszE46boA79tyW5aQpEF1LpqREvJy127uurJKPCe61JSS4UT%2BW5fDJDSHjgjc9Qsd8Zzj9IQA9Z68B_OydVf%2Bnk01_Ss2nSIyxZcV73p3w%2BTCoc6J3PVdjFYtonRiMCIvvPEEJUOnaCh9BcxLgEvU44JnYj8991UVdPC_3u2C%2BlvAG_SDI7fiuHvHNTKC9ompveJMjKD69AGSAZUvD_Kl5GN3uNjNA22rUcr0wqOw9BibQdLydGb%2Bbr

Response:

<PAYLOAD><NAME>vCard unprotected</NAME><PIN>0</PIN><DATA>r6QEsUVaVGZOm9MVWDszHo_0vzrHpAndKDpLHSSHyAZULyRvgP+wN7DHcbFDPjsFOoTMGCswJXWBifsdzb0Pp1A4Sw9CjLRFaC8oCJezj3z7niaDZBR7HS2o_1FiZXxun5PHapHbEKVEKUZpKunHdUo9OxjV2KUqwdIJ3F0zIn43lNINNhJ0aO6Ryj7FrQqgWChJEU3WlwFeK1obio6qQKjLetIqMxw_S4bRfUogOAXwx+M8y7cErTw+XAA27sQbUCU4coD_0wSelQ2CYw8rIxrjiFxUKCIOhY63Rd_EcqJaMTs$</DATA></PAYLOAD>

URL

Request:

GET /7JGMIVQUKMNDPCW5ET5CRG4JP4KB35LK.aspx?Level=1&VID=1%2B71&TH=_%2BxrkrK8FE1mhNkWheA%24&PL=sNsc3yQ5RQU%2B9IVKZBI5d%2B6Q2HmepDnPZWwqF1zsxQclJz99iPC0Lb3GHdokQCRwL%2B7BClFOSA7s66FQv9p12DVIUgQ_8N92JSMzCITt2TuyuBGkQCFZB1KRyXwwSUYK4p3dXr7efdM5QkV1T_LFdCJfQgDhitAqyN5qvUA9SmAp881%2BN0xQAuPqvljItQvbKDlDCEiKvAVfTkFolJ6yMsLKHaQmAj8QTPSZXTNPPR_th6hAubgc2UBMVQ9PjNgLJSdUZIDw

Response:

Location: http://wap.ecw.de

Hier eine kurze Anmerkung: Bei einer URL wird im HTTP-Header ein Location-Feld zurückgeliefert. Sobald der Tag mit der Software geladen wurde und Microsoft die Antwort liefert, wird der Standard-Browser des Handys aufgerufen – ohne Nachfrage! Sicherheitstechnisch äußerst bedenklich – man stelle sich nur mal vor, dass man z.B. eine Bank mit einer falschen URL taggt. Der Benutzer nimmt das Tag auf, der Browser öffnet sich und der Nutzer sieht die gefälschte Bank-Seite.

vCard (mit Passwort)

Request:

GET /KV4PWBAKHRXTHEGERKNRYY3YKY4PIMYZ.aspx?Level=1&VID=1%2B71&TH=_%2BxrkrK8FE1shOYWheA%24&PL=u6Ad3j4pJwMiiPcxZAsqBO2GzWTuvHS7FghEEkeI3g4uXD58kuDWK6G6b6EkWTcDLPjUCSFXN3qfj89VpL5u0T4zUwUl4L1wOV9Bc4T0ykixrgSnMDgmcyH1p3krLV0D6ebcX6TOH9UlPjcOT%2BvWByFJVwORk69eu7oEuFtZUWkiiMx_LVwyBP%2BWzCPIrBioKy9WCziTw3EsKi9tj_qpO8mxHKU8El0WUIjrJjNWLmzukb1DyaFjrTMoOwpU6MMCLlxVZZrg

Response:

<PAYLOAD><NAME>vCard protected</NAME><PIN>1</PIN><DATA>s61ur1A7XGooj8JqXDc9HIPlxTnMvxujU1pdGjOKug5IJk5xlZ64O9bTYM5HMjUHNpW2GyArNwv66e0a2rB9r0wxIRFX7bxJDjs5d5O_gX73j1yAbw9pY1bI6VZ1aA5mg5qtdIS6GKkiPVcWLuXJd0YsQRvew7dUurIf20o+UHYrnbgTI3N8ZIiF20HBoQSiVDkzEkbNhX8lS0wcnYPYSLTCEMw_UhQzLZLAAk4sNgf81pk_wKwW00deSgch47YTTCxSbJWe2wj4gRz9ZwMlIRby8l9fMzBw_u6hQsjJAKpGOFE$</DATA></PAYLOAD>

Freitext
Request:

GET /I6YA3RA6VSFCYMAO5AI7XYQAZKBJNJZD.aspx?Level=1&VID=1%2B71&TH=_%2BxrkrK8FE1vhN4WheA%24&PL=pKQToEA4JxxD7IQ6exQsDI2Iwh3ipma9bA9VGUCIqQsxWDAC7PHWNMDeHKo7RjELTPbbdS1MSHzliN5eo74Z1CE3XXtb8b1vWDsyeJvrzEDRoAvbPCNZdVvytnIsLSoG9uLSIdrfH8pEWkQFUPTQD0FHWH%2BdiNBYwb0Vs1xZJmw9jMIBU00yG57yvyjXsx6gSyFZdzSIvHdWLT5miPrePta1EttCA10JMeyYLSxJKGSOn7I_xbocq0kvKgFT6LQHMVhbG%2BTx

Response:

<PAYLOAD><NAME>Free Text</NAME><PIN>0</PIN><DATA>r6QEsUVaVGZOm9MVWDszHo_0vTzeonHOUytWESKQ3gVLLjl5kfK5IsvFGaJYLDsPHq_pOTExB1i37Mo4z70FoCc$</DATA></PAYLOAD>

Anmerkungen
Die zu ladende Datei (….aspx) und der GET-Parameter “TH” ergeben eventuell die ID. Ich habe zwei verschiedene Schnappschüsse des FreeText-Tags gemacht und jedesmal war die ASP-Seite und der TH-Parameter identisch. Der PL-Parameter änderte sich hingegen. Liefert Microsoft da eventuell irgendwelche GPS-Koordinaten mit? Ich kann leider die Daten nicht entschlüsseln – die Strings scheinen zwar Base64-codiert zu sein. Ein Encoding brachte aber kein verwertbares Ergebnis.

Vielleicht kann irgendwer mit diesen Erkenntnissen etwas anfangen. Viel interessanter fände ich es, wenn man seinen eigenen Tag-Provider hinterlegen könnte und wenn das Protokoll vor allem offen und standardisiert wäre.

Btw: Mit Hilfe des Tags könnte man z.B. eine Türklingel für das Eingangsschild der Wohnung realisieren: Tag an das Namensschild, Gast ent-taggt das Foto, Windows Live ruft eine URL auf dem Home-Server des Gastgebers auf. Das dahinter-hinterliegende Script startet den Musik-Player… Eigentlich ganz cool 🙂