Friday, December 18, 2020

Węzeł Krajowy w .NET/C# na github

Na github powstało repozytorium, w którym znajdzie się implementacja klienta .NET dla Węzła Krajowego, OldMusicBox.EIH.Client (EIH jest tu skrótem od Electronic Identification Hub, ten termin wygląda na zamiennie używany z Electronic Identification Node).

Monday, December 14, 2020

Węzeł Krajowy w .NET - kamień milowy

Od ostatniego posta na temat Węzła Krajowego minęło sporo czasu, niestety, było tysiąc i jeden rzeczy do zrobienia i temat musiał czekać na swoją kolej.
Udało się wygospodarować trochę czasu w piątek 11.12 i dziś i z przyjemnością puszczam w eter wiadomość, że kod działa od początku do końca i odzyskuje dane logowania użytkownika w .NET. Pozostaje całość posprzątać, zrefaktoryzować i pozostawić tu i ówdzie furtki na zachowania nieprzewidziane - na tę chwilę działa to tylko z witryną symulatora.
Po raz kolejny wypada pozazdrościć Koleżeństwu programującemu w Javie, ponieważ tam wygląda to na dużo prostsze, w szczególności w ostatnim kroku dekodowania zaszyfrowanej asercji można się wzorować na załączonym przykładowym kodzie w Javie. Niestety, programując w .NET trzeba umieć całość przenieść na odpowiadające elementy biblioteki standardowej i Bouncy Castle. I to niestety, nie jest najłatwiejsze.
Stosowny kod zostanie w niedługim czasie opublikowany na github.

Tuesday, October 27, 2020

Materiały edukacyjne - funkcje w Javascript

Czwarty wykład z Wybranych elementów praktyki projektowania oprogramowania, o programowaniu funkcyjnym w Javascript, to jeden z moich ulubionych, łącznie z kolejnym o obiektowości prototypowej. Tu opowiadam o tym jak w Javascript zobaczyć język funkcyjny, z takimi elementami funkcyjnymi jak funkcje wyższych rzędów, rekursja, domknięcia, kontynuacje. Zrozumienie tych elementów języka znacznie ułatwia swobodne poruszanie się w bibliotekach UI, takich jak React (komponenty funkcyjne).
Zapraszam do oglądania.

Friday, September 11, 2020

Węzeł Krajowy w .NET - rozpoczęcie pracy

Rozpocząłem prace zmierzające do wsparcia Węzła Krajowego w bibliotece klienckiej SAML2/ePUAP. Podstawą pracy jest dokument Instrukcja integratora DU opublikowany przez COI.
Po rozwiązaniu problemów z SAML2 przy integracji z ePUAP, integracja z WK wnosi kolejny poziom wyzwania. W szczególności:
  • Węzeł Krajowy wymusza kryptografię opartą na certyfikatach eliptycznych (ECDSA). Problem jest taki że o ile biblioteka standardowa .NET obsługuje szyfrowanie/deszyfrowanie na takich certyfikatach, SignedXml już nie - w metodzie ComputeSignature można wprost podejrzeć if-a, który sprawdza typ certyfikatu i jeśli to nie jest RSA, wyrzuca wyjątek. Jest to poważne zaniedbanie!, z którym niełatwo sobie poradzić (kto ma ochotę na napisanie samodzielnie implementacji podpisywania XMLi, która obsługuje wszystkie niuanse, transformaty, itd. i przy okazji dodaje obsługę certyfikatów eliptycznych?)
  • Węzeł Krajowy upraszcza komunikację bo nie wymaga dodatkowego kroku z wołaniem usługi, ale za to - asercje o użytkowniku zwraca w postaci zaszyfrowanej. Problem w tym że na tę chwilę nie mam pojęcia jak to chwycić w C#
  • Na dzień dzisiejszy jest kawałeczek sukcesu, taki pierwszy set z trzech. Mianowicie, potrafię wygenerować sygnaturę tak żeby AuthnRequest był poprawnie obsłużony. Jeśli to komuś pomoże, to używam Bouncy Castle i uwaga - wbrew intuicji nie można używać signera SHA256WITHECDSA tylko SHA-256withPLAIN-ECDSA - straciłem na tym kilka godzin.
    W kolejnych dniach dalsza część pojedynku...

    Monday, August 24, 2020

    OldMusicBox.ePUAP.Client 0.64

    Biblioteka kliencka dla ePUAP, OldMusicBox.ePUAP.Client w aktualnej wersji domyka zagadnienie komunikacji za pomocą usługi Skrzynek Podawczych. Konkretnie - usługa WS-Doręczyciel::dorecz umożliwiająca wysyłanie powiadomień na skrzynki użytkowników z Urzędowym Potwierdzeniem Doręczenia (UPD) otrzymała wsparcie w generowaniu takich powiadomień.
    Konkretnie, WS-Doręczyciel::Dorecz wymaga aby przekazywany dokument był podpisany podpisem kwalifikowanym w standardzie XAdES. Jako że C# nie posiada natywnego wsparcia dla sygnatur XAdES, trzeba popracować na poziomie niżej, na poziomie SignedXml i wymagane przez XAdES węzły złożyć sobie samodzielnie. ePUAP zadowala się najprostszym wariantem sygnatury.
    Drugi element wsparcia dotyczy szablonu pisma ogólnego, które umożliwia przesłanie dowolnej treści z załącznikami binarnymi (np. PDF) i wizualizuje się na witrynie ePUAP dzięki istniejącej tam transformacie. Załączony przykład pokazuje jak wygenerować dokument w tej składni.
    Połączenie obu mechanizmów pozwala zbudować infrastrukturę dla przesyłania podpisanych dokumentów do użytkowników końcowych ePUAP (osób fizycznych).

    Friday, May 29, 2020

    SessionAuthenticationModule::OnAuthenticateRequest is broken

    Relying on base class library modules should be safe. Unless it's the SessionAuthenticationModule that misses correct handling of some edge cases. Here's the story.
    We use the SessionAuthenticationModule for ages. It's great and reliable in 99.99% of cases. However, there could be a case where there's something wrong with the cookie. The cookie is there but it has been somehow altered in the browser. Either it doesn't contain a valid base64 stream or the stream is valid but there's no XML inside the stream.
    The problem is that the SAM first tries to decode the cookie
    protected virtual void OnAuthenticateRequest(object sender, EventArgs eventArgs)
    {
     HttpApplication httpApplication = (HttpApplication)sender;
     HttpRequest request = HttpContext.Current.Request;
     SessionSecurityToken sessionSecurityToken = null;
     if (!TryReadSessionTokenFromCookie(out sessionSecurityToken) && string.Equals(request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
     {
                   ..
    
    Now, guess what happens when TryReadSessionTokenFromCookie throws an exception? Well, the exception is not caught and thus it's escalated to your code. And now
    • what your code does when an exception occurs? You catch it by a top level exception handler and you possibly shows a generic error page.
    • what a user does when they see the error page? They refresh the browser.
    • is the error gone? Nope, the flawed cookie is still there
    What you get is a nice stacktrace of the problem
       w System.Convert.FromBase64_Decode(Char* startInputPtr, Int32 inputLength, Byte* startDestPtr, Int32 destLength)
       w System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength)
       w System.Convert.FromBase64String(String s)
       w System.IdentityModel.Services.ChunkedCookieHandler.ReadInternal(String name, HttpCookieCollection requestCookies)
       w System.IdentityModel.Services.ChunkedCookieHandler.ReadCore(String name, HttpContext context)
       w System.IdentityModel.Services.CookieHandler.Read(String name, HttpContext context)
       w System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
       w System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
    
    My first attempt to this was to replace the cookie handler by a custom cookie handler. It's not that obvious how to do that but anyway
    public class CustomCookieHandler : System.IdentityModel.Services.CookieHandler
    {
        private CookieHandler _handler; // = new ChunkedCookieHandler();
    
        public CustomCookieHandler(CookieHandler handler)
        {
            if ( handler != null )
            {
                this._handler = handler;
    
                this.Name       = handler.Name;
                this.Path       = handler.Path;
                this.RequireSsl = handler.RequireSsl;
            }
            else
            {
                throw new ArgumentNullException();
            }
        }
    
        // public override 
    
        protected override void DeleteCore(string name, string path, string domain, HttpContext context)
        {
            _handler.Delete(name, path, domain, context);
        }
    
        protected override byte[] ReadCore(string name, HttpContext context)
        {
            try
            {
                return _handler.Read(name, context);                
            }
            catch
            {
                return null;
            }
        }
    
        protected override void WriteCore(byte[] value, string name, string path, string domain, DateTime expirationTime, bool secure, bool httpOnly, HttpContext context)
        {
            _handler.Write(value, name, path, domain, expirationTime, secure, httpOnly, context);
        }
    }
    
    This could be plugged into the pipeline somewhere early with
    FederatedAuthentication.FederationConfigurationCreated +=
            ( s, fede ) =>
            {
                fede.FederationConfiguration.CookieHandler = new CustomCookieHandler(fede.FederationConfiguration.CookieHandler);
            };
    
    Case closed? Not really, looks like the base64 cookie data can be valid but what comes out is not XML and is not parsed! The exception changes to
       w System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, XmlException exception)
       w System.Xml.XmlUTF8TextReader.VerifyNCName(String s)
       w System.Xml.XmlUTF8TextReader.ReadQualifiedName(PrefixHandle prefix, StringHandle localName)
       w System.Xml.XmlUTF8TextReader.ReadStartElement()
       w System.Xml.XmlUTF8TextReader.Read()
       w System.Xml.XmlBaseReader.MoveToContent()
       w System.IdentityModel.Services.SessionAuthenticationModule.GetKeyId(Byte[] sessionCookie)
       w System.IdentityModel.Services.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
       w System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
       w System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
    
    What this custom cookie handler should do would be then to make sure whatever is read, can be interpreted as XML further down. But this would slow down the custom cookie handler dramatically! Each time a cookie is read, it would be first tried to contain an XML by my custom code and then read as XML again by the existing code.
    An ultimate solution? Delete your SAM cookies in the error page. As simple as that. A side effect is users are logged out of the application after an exception is caught by the top level exception handler.

    Thursday, May 21, 2020

    Materiały edukacyjne - Repository, Unit of Work

    Jak implementować wzorce Repository i Unit of Work żeby architekturze pomagać a nie przeszkadzać?

    Corona hobbies

    It's not that you should only stay home and work remotely. It's a perfect time to spend time on your hobbies. My primary hobby is music and I wish I could spend more time practicing.

    Thursday, May 14, 2020

    Materiały edukacyjne - Inversion of Control

    O tym czym jest Inversion of Control, czym jest kontener Dependency Inversion, jak go używać, czym jest Service Locator i dlaczego jest antywzorcem i wreszcie, dlaczego ultymatywnym rozwiązaniem dla architektury opartej o DI jest Local Factory.

    Monday, May 4, 2020

    OldMusicBox.ePUAP.Client 0.60

    Biblioteka kliencka OldMusicBox.ePUAP.Client nad którą pracuję w wolnych chwilach osiągnęła kolejny ważny punkt rozwoju. Do tej pory za pomocą biblioteki możliwe było logowanie przez Profil Zaufany oraz obsługa funkcji do podpisywania dokumentów przez ePUAP.
    W wersji 0.60 która została opublikowana na NuGet biblioteka dodaje podstawowy zakres wsparcia w komunikacji z usługą Elektroniczne Skrzynki Podawcze (ePUAP ESP). Podstawowy zakres obejmuje na tę chwilę
    • WS-Skrytka
      • Nadaj
    • WS-Pull
      • DokumentyOczekujace
      • PobierzNastepny
      • PotwierdzOdebranie
    • WS-ZarzadzanieDokumentami
      • DodajDokument
    W kolejnych wersjach zostanie dodane wsparcie dla podstawowych usług, w tym WS-Doreczyciel i WS-obslugaUPP.
    Przypominam że kod jest publikowany na licencji AGPL i jako taki ma charakter wyłącznie edukacyjny/niekomercyjny. Proszę o kontakt w razie potrzeby wykorzystania tej implementacji do innych celów.

    Wednesday, April 29, 2020

    Materiały edukacyjne - WPF

    Tym razem programowanie pod Windows i wprowadzenie do WPF z przykładami.

    Thursday, April 23, 2020

    Materiały edukacyjne - wzorce czynnościowe

    Nowe materiały edukacyjne dodawane są na bieżąco, dlatego zachęcam do zaglądania na profil na YouTube. Na zachętę - materiał poświęcony wzorcom komunikacyjnym, można dowiedzieć się czym różnią się Mediator, Observer i Event Aggregator. Na deser Memento i pomysł na Undo/Redo.

    Wednesday, March 25, 2020

    Koronawirus - dodatkowe materiały edukacyjne

    Zajęcia stacjonarne w Instytucie informatyki UWr, gdzie pracuję, nie odbywają się z wiadomych powodów. W związku z tym przygotowuję dla studentów materiały online i są one dostępne publicznie.
    Aktualnie, w semestrze letnim prowadzę dwa wykłady, Programowanie pod Windows i Projektowanie obiektowe oprogramowania. Zapraszam do obejrzenia materiałów obu wykładów. Jeśli ograniczenia zostaną utrzymane, należy spodziewać się kolejnych wykładów udostępnianych w ten sposób.

    Tuesday, February 18, 2020

    OldMusicBox.ePUAP.Client released to NuGet

    The ePUAP Client has been released to NuGet. It allows your app to perform the SSO but it also shows how to sign arbitrary XML documents using AddDocumentToSigning/GetSignedDocument functions.
    The documentation as well as an example application are provided at the GitHub project page.
    I hope this would be usedful for anyone who wants to learn how ePUAP integration works. The next step is Węzeł Krajowy.

    Monday, February 17, 2020

    OldMusicBox.ePUAP.Client milestone reached

    I am happy to announce that the ePUAP client library, the OldMusicBox.ePUAP.Client has reached its first important milestone where you can actually single sign on to your app through ePUAP.
    This means that all three steps work correctly:
    1. The SAML2 AuthnRequest is correctly issued
    2. The SAML2 ArtifactResolve is correctly issued
    3. The ePUAP getTpUserInfo is correctly called
    The road map for few days is:
    • Add support for Single Log Out (LogoutRequest, LogoutResponse)
    • Add support for document signing (tpSigning interface)
    • Release the Client to NuGet
    Please note that while the SAML2 component is licensed under the MIT license, the ePUAP Client is licensed under the AGPL-3. However, you are free to download the code and use it according to the license. Any issues or feature requests are welcome.

    Tuesday, February 11, 2020

    OldMusicBox.ePUAP.Client announcement

    I've just created a repo for the upcoming independent .NET ePUAP Client. The goal here is to provide an open source implementation under AGPL-3.0 license. Please keep your fingers crossed and expect working code in a week or two.

    Monday, February 10, 2020

    OldMusicBox.Saml2 0.65 published

    I hereby announce that the very first public version of the SAML2 library has been published on NuGet. This first release contains the core part of the SAML2 client interface, including REDIRECT/POST/ARTIFACT binding and LogoutRequest/LogoutResponse support.
    The next step is to build the ePUAP client library on top of this SAML2 implementation. I will officially announce it in a couple of days.

    Tuesday, January 28, 2020

    An independent SAML2 client/server library

    I started to work on an independent SAML2 client/server library that would target classic .NET Framework. The source code is available on GitHub, the repo's name is OldMusicBox.Saml2. I decided to release it under MIT license.
    The long-time goal is to cover most SAML2 features and target .NET Core.
    The short-time goal is to have basic features quickly so that it's possible to use this in other projects. In particular, based on feedback I get from people, I believe the community needs an independent Profil Zaufany client library. This one, when it's ready, will be released under more strict license (so that I could control where and how it's used). The plan is to make it available in few weeks and somewhere in future add the support of the Krajowy Węzeł Identyfikacji Elektronicznej.