Auth0 – Aplikacja do odpalania rakiet – backend

Kontrola dostępu

Niestety w obecnej postaci dowolna osoba w internecie jest w stanie anonimowo wywołać metody naszego serwisu.

Aby włączyć obsługę kontroli dostępu należy do metod Configure i ConfigureServices klasy Startup dodać następujący kod:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddAuthentication();
    services
        .AddAuthorization();
    services
        .AddMvc()
        .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseAuthentication();
    app.UseMvc();
}

Metody AddAuthentication i UseAuthentication – sprawiają, że aplikacja wspiera autentykację – czyli będzie próbować zidentyfikować użytkownika który się łączy z aplikacją. Bez identyfikacji użytkownika weryfikowanie kontrola dostępu jest niemożliwa, czasami jednak identyfikowanie użytkownika bez kontroli dostępu ma sens (np. w celach statystycznych).

Metoda AddAuthorization – sprawia, że aplikacja wspiera autoryzację czyli kontrolę dostępu.

Framework Mvc umożliwia selektywne włączenie kontroli dostępu, domyślnie wszystkie akcje wszystkich kontrolerów są dostępne publicznie. Aby ograniczyć dostęp tylko dla zalogowanych użytkowników należy dodać wpis:

using Microsoft.AspNetCore.Authorization;

w sekcji using kontrolera oraz linijkę [Authorize] nad metodą kontrolera:

public class IndexController : Controller
{
    [Authorize]
    [HttpGet]
    [Route("missile-types")]
    public IActionResult GetMissileTypes()
    {
    	...
    }
    ...
}

Atrybut Authorize może też być użyty nad całym kontrolerem sprawi to że wszystkie metody kontrolera będą wymagały kontroli dostępu

[Authorize]
public class IndexController : Controller
{
...
}

Jeżeli wszystkie akcje wszystkich kontrolerów wymagają autoryzacji, można darować sobie dodawanie atrybutu Authorize w każdym z nich i zmodyfikować klasę Startup tak też zrobiłem.

Najpierw dodałem dwa wpisy w sekcji using:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;

oraz zmodyfikowałem użycie metody AddMvc

services.AddMvc(o =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    o.Filters.Add(new AuthorizeFilter(policy));
})
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));

Linijka „o.Filters.Add” dodaje element do listy „Filtrów”. Filtry to obiekty klas implementujących interfejs IFilterMetada (dużo trudnych słów, dla kogoś, kto zaczyna programować). Filtry mogą być wywoływane przed/po albo zamiast akcji kontrolera i modyfikować wynik akcji, albo dostarczać jej parametrów. Jednym z filtrów jest AuthorizeFilter, który działa podobnie jak dodanie atrybutu Authorize. Jako parametr konstruktora akceptuje on politykę. Politykę da się stworzyć przy pomocy metody build klasy AuthorizationPolicyBuilder, może on być bardzo rozbudowana jednak w naszym przypadku, wymagamy tylko aby nie dało się dokonywać anonimowych wywołań metod, użyłem więc metody RequireAuthenticatedUser.

Próba pobrania listy typów pocisków na tym etapie rozwoju aplikacji powoduje wystąpienie błędu:

Błąd wynika z faktu iż istnieje wiele różnych metod identyfikacji użytkownika, a nasz kod nie wskazuje, która ma być wykorzystana.

Większość z metod opiera się na nagłówku Authorize wywołania. Przeglądarki nie pozwalają użytkownikom łatwo dodawać nagłówków, jednak bardzo łatwo da się to zrobić z kodu aplikacji. W większości technologii wygląda to mniej więcej tak:

request.headers.add('Header', 'Header-content')

Nagłówek Authorize składa się z dwóch elementów: typu poświadczeń i samych poświadczeń oddzielonych spacją. Najprostszym typem jest Basic. Polega on na rozdzieleniu loginu i hasła dwukropkiem i zakodowaniu w base64. Np. autoryzacja użytkownika o loginie admin i haśle „kopytko” wygląda następująco:

request.headers.add('Authorize', 'Basic YWRtaW46a29weXRrbw==')

Autoryzacja typu Basic ma jednak wiele wad min. fakt iż login i hasło są przesyłane na prawo i lewo, co może prowadzić do wycieku.

Współcześnie powszechnie wykorzystywana jest metoda JWT (Json Web Tokens). Aby wskazać, że aplikacja używa do autoryzacji JWT jako typ autoryzacji należy podać 'Bearer’, poświadczenia – token składa się z trzech sekcji rozdzielonych kropkami. Pierwsza sekcja to nagłówek – dokument json zakodowany w base64 zawierający dane techniczne. Druga sekcja to także dokument json zakodowany w base64, zawiera on dane związane z kontrolą dostępu, często zawiera on dane użytkownika jego nazwę, email, przypisane role czy zakres uprawnień, powinien też zawierać takie dane jak: adresat (aud – audience) – serwis na potrzeby, którego token został wystawiony – inne serwisy powinny odrzucać token nie adresowany do nich, wystawcę (aut – authority), termin wygaśnięcia (exp – expiry) – termin po którym token nie powinien być akceptowany, klejmsy (claims) – słowo nie dające się łatwo przetłumaczyć – są to inne dane związane z użytkownikiem lub sesją – najłatwiej jest je zrozumieć na przykładzie facebooka – Aplikacja korzystająca z API facebooka może działać w imieniu użytkownika – np. udostępniać coś na jego tablicy. Aby to było możliwe aplikacja musi posiadać token, gdyby nie było pola claims token umożliwiałby aplikacji robiebie z kontem co by chciała, np. analizowę prywatne wiadomości. W polu claims może znajdować się zakres uprawnień aplikacji, która prosząc o token musi ten zakres podać, użytkownik ma do nich wgląd i może je zakaceptwać. Aplikacja może z tym tokenem dodawać wpisy na ścianie, jednak gdy spróbuje połączyć się z serwisem wiadomości prywatnych, zostanie grzecznie ale stanowczo spuszczona na drzewo.

Ostatnią częścią tokenu jest podpis cyfrowy zakodowany w base64, gwarantujący, że reszta tokenu nie była modyfikowana od momentu wystawienia.

Obsługa identyfikacji przy pomocy Tokenów jest dobrze wspierana w .net. Aby ją dodać należy dodać wpis w sekcji using klasy Startup

using Microsoft.AspNetCore.Authentication.JwtBearer;

oraz zmodyfikować użycie metody AddAuthentication.

services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.Authority = "";
        options.Audience = "";
    });

Właściwości options.DefaultAuthenticateScheme options.DefaultChallengeScheme określają typ autoryzacji jakiego oczekuje aplikacja, JwtBearerDefaults.AuthenticationScheme ma wartość „Bearer”.

Metoda AddJwtBearer określa szczegóły weryfikacji tokenu, dwa podstawowe parametry to Authority – akceptowany wystawca tokenu i Audience – identyfikator serwisu znany przez wystawcę. Aby uzupełnić te pola należy zarejestrować ten serwis – API.

Auth-0 aplikacja do odpalania rakiet – frontend

Rejestracja aplikacji

Aby aplikacja mogła się łączyć z auth0 należy ją zarejestrować. W tym celu w panelu administracyjnym tenanta należy wybrać zakładkę „Applications”. Auth0 tworzy domyślną aplikację dla rejestrowanego tenanta, można ją wykorzystać i tak właśnie zrobiłem. Po kliknięciu w nazwę aplikacji zostaje wyświetlony formularz z całą masą pól:

  • Name – nazwa – ja ją zmieniłem na Rocket launcher – frontend
  • Domain – adres w domenie auth0 związany z tą aplikacją
  • Client ID – identyfikator aplikacji – może być umieszczony w aplikacji klienckiej, a nawet w kodzie źródłowym dostępnym publicznie
  • Client Secret – token pozwalający na wykonywanie wrażliwych operacji (np. pozyskanie tokenu bez podawania loginu i hasła, albo do utworzenia konta użytkownika) na Api auth0
  • Application Type – służy do zmiany widocznych pól na formularzu, część pól ma sens tylko w przypadku określonych aplikacji, pole zostaje czasami zablokowane po wybraniu opcji i zapisie.
  • Allowed Callback URLs – lista adresów, na które użytkownik może być przekierowany po wprowadzeniu poprawnych poświadczeń – utrudnia przechwycenie danych autoryzacyjnych przez obce aplikacje, należy wprowadzić wszystkie adresy pod które może nastąpić przekierowanie, ponieważ moja aplikacja działa tylko na moim laptopie wprowadziłem tutaj adres http://localhost:8080/logged-in
  • Allowed Web Origins – pole wykorzystywane gdy chcemy utrzymywać ekran logowania na swoim serwerze. Ponieważ korzystam z ekranu logowania udostępnionego przez auth0 zostawiam to pole puste
  • Allowed Logout URLs – lista adresów URL pod jakie użytkownik może być przekierowany po wylogowaniu się. Ja wprowadziłem 
    http://localhost:8080/logged-out
  • Allowed Origins – pole związane z CORS ja wpisałem http://localhost:8080

Auth0 – Delegowanie zarządzania tożsamością

Kiedy delegować autoryzację?

Czytając dokumentację techniczną Auth0 oraz przygotowując aplikacje wykorzystujące tego dostawcę, da się dostrzec scenariusze, w których delegowanie zarządzania kontami użytkowników jest jednoznacznie dobrą decyzją.

Dostawca oferuje (prawie)dokładnie to czego potrzebujemy

Większość dostawców tożsamości zaadresowało bardzo szeroki zakres wymagań. Konfiguracja dostawcy zajmuje znacznie mniej czasu niż pisanie autorskiego rozwiązania. Co może być szczególnie ważne w początkowej fazie projektu, gdzie każda godzina opóźnienia w budowie, może decydować o tym czy okaże się on sukcesem czy porażką.

Nie znamy wymagań

Innym problemem występującym na wczesnym etapie tworzenia projektu jest sytuacja, w której często nie znamy wymagań dotyczących autentykacji np. zakresu gromadzonych danych użytkownika. Tworzenie własnego rozwiązania, które następnie zostanie przepisane jest marnotrawstwem zasobów, a podpięcie zewnętrznego dostawcy w domyślnej konfiguracji jest ekstremalnie szybkie.

Należy też dodać że większość pracy wymaganej do integracji z zewnętrznym dostawcą tożsamości nie różni się od integracji z autorskim rozwiązaniem. W optymistycznym przypadku migracja do innego dostawcy, albo autorskiego rozwiązania polega na zmianach w pliku konfiguracyjnym.

Niektórzy twierdzą, że na bardzo wczesnym etapie można wcale nie zabezpieczać serwisu. Podpięcie autentykacji w późniejszym etapie powoduje powstanie błędów regresji – wiele modułów przestaje działać. Istnieje też ryzyko pominięcia zabezpieczenia całych modułów, lub ich części.

Relatywnie wysokie koszty utrzymania autoryzacji

Idealne oprogramowanie robi to co robić powinno i nie wymaga zmian. Posiadanie własnego mechanizmu autoryzacji może wymusić wprowadzenie zmian w aplikacji, a te zmiany pociągają za sobą inne koszty, takie jak przeprowadzenie testów regresji czy wdrożenia.

W takim wypadku wykorzystanie zewnętrznego dostawcy może być tańsze.

Czego nie należy się bać?

Oczywiście sytuacja nie zawsze jest różowa, są sytuacje, w których integracja wiąże się dodatkowymi kosztami, może być jednak ciągle opłacalna.

Niestandardowa rejestracja użytkownika

Większość dostawców dostarcza pustej bazy użytkowników i umożliwiają rejestrację w systemie dowolnej osobie. Są to jednak tylko ustawienia domyślne, rejestrację można wyłączyć jednym kliknięciem. Można też napisać własne ekrany logowania/rejestracji, robiąc to tracimy jednak jeden z powodów dla których decydujemy się na delegowanie.

Integracja z serwisami społecznościowymi

Jedyne czego, w celu integracji z facebookiem, wymaga wielu dostawców to kliknięcie w jeden przełącznik i uzupełnienie formularza. Niestety formularz zawiera kilka pól, których wypełnienie wymaga przebicia się przez biurokrację tej firmy. Przez biurokrację trzeba przejść także przy pisaniu własnego mechanizmu, jej udział sprawia jednak, że zysk wynikający z delegacją jest mniejszy.

Inne portale społecznościowe także wymagają przejścia przez biurokrację, zajmuje to jednak mniej czasu.

Import kont użytkowników

Istnieją dostawcy którzy oferują możliwość importu danych użytkowników. Może to się jednak wiązać z pewnymi niedogodnościami dla użytkownika. Auth0 nie umożliwia importu haseł, więc nawet jeżeli jakimś cudem je posiadamy to dostawca je zignoruje, a użytkownik i tak będzie musiał ustawić hasło przy kolejnym logowaniu.

Vendor locking

Napisałem wcześniej, że w optymistycznym przypadku zmiana dostawcy wymusza tylko aktualizację konfiguracji aplikacji. Problem w tym, że optymistyczne przypadki zdarzają się rzadko. Dostawcy dostarczają własnych bibliotek ułatwiających integrację, jednak ich użycie sprawia, że przesiadka jest trudniejsza.

Jeżeli mamy użytkowników, którzy na swoich maszynach, czy to typu dektop, czy to smartfonach, uporczywie używają starej wersji oprogramowania, migracja może oznaczać ich utratę.

Rozstanie jest trudne, jednak nie niemożliwe. Potwierdza to historia zespołu, który zbudował własnego dostawcę autoryzacji gdy dostawca nie dawał rady obsłużyć ruchu przez nich generowanego. Oznacza to, że pomimo tak długiej relacji, byli w stanie zakończyć ten związek.

Przekierowania na inną domenę

Domyślnie dostawcy tożsamości wymagają przekierowania na stronę w ich domenie albo użycia elementu iframe. Takie zachowanie aplikacji budzi podejrzenia szczególnie ostrożnych użytkowników, ponieważ z podobnych metod korzystają hackerzy w atakach typu phishing. Zachowanie to da się nadpisać ale wymaga to dodatkowej pracy.

Kiedy nie delegować?

Wymagania prawne

Jeżeli prawo, albo regulacje w organizacji, zabraniają przetrzymywania danych użytkowników po za własnymi serwerami, użycie zewnętrznego dostawcy jest niemożliwe albo znacznie utrudnione.

Koszta

Większość dostawców tożsamości działa w modelu SaaS co oznacza że miesięczna opłata zależy od ilości użytkowników i zakresu funkcjonalności. W szczególnych przypadkach, takich jak ekstremalnie duża ilość użytkowników, może się okazać, że napisanie własnego rozwiązania i utrzymywanie kont we własnym data-center będzie znacznie tańsze.

Niestandardowe mechanizmy autoryzacji

Istnieją rozwiązania techniczne utrudniające integrację z zewnętrznym dostawcą:

  • komunikacja z oprogramowaniem działającym w  intranecie, np. usługą katalogową (Active Directory/Open LDAP), jest utrudniona, administrator sieci powie Ci czy jest możliwa.
  • autoryzacja z wykorzystaniem programów klienckich – najpopularniejsze rozwiązanie do obsługi podpisów cyfrowych w Polsce wymaga uruchomienia apletu Javy, integracja z tą technologią, nawet bez uwzględnienia zewnętrznego dostawcy tożsamości, jest trudna. 

Czy delegować?

Przez wiele lat każdy własny projekt zaczynałem od napisania mechanizmu autoryzacji, a wiele z nich skończyło się na tym etapie. Wygląda na to, że kolejne będę zaczynał od integracji z dostawcą wykorzystując najtańszy możliwy plan i przechodził czym prędzej do rozwiązywania problemów biznesowych.

Recenzja Noblechairs HERO Gaming skórzany

Montaż

Montaż krzesełka był zaskakująco prosty. Wystarczyło wykręcić 3 śruby i wkręcić 11, nie trzeba mieć żadnych narzędzi ponieważ zestaw zawiera narzędzie będące połączeniem śrubokręta krzyżakowego i klucza imbusowego wystarczające do montażu. 

Na początek należy odkręcić 3 śruby od spodu siedziska i wykorzystać je do przykręcenia podłokietnika. Drugi podłokietnik był już przykręcony.

W moim egzemplarzu jedna ze śrub wchodziła krzywo w otwór, z którego ją wykręciłem. Po kilku próbach jednak się udało. Chciałbym tutaj zwrócić uwagę na dosyć solidną blachę przyspawaną pośrodku siedziska. Służy ona ochronie 4 liter właściciela w przypadku wystrzelenia siłownika pneumatycznego.

Kolejnym etapem jest przymocowanie części odpowiedzialnej za możliwość bujania się i regulacji wysokości siedziska. Wymaga to przykręcenia 4 śrub imbusowych.

W tym momencie powinienem także zamontować takie plastikowe rączki na te aluminiowe osie wystające po bokach, ale zrobiłem to później.

Jak w każdym krześle montaż kółek i siłownika nie wymaga żadnych śrub, kółka wchodzą lekko i trzymają się pewnie, problemem może być wycelowanie siedziskiem w siłownik ponieważ Jest ono znacznych rozmiarów i wagi.

Podczas montażu oparcia należy uważać żeby nie przyciąć sobie paluchów, ponieważ jedna z szyn, do których się je montuje, jest połączone z bardzo silną sprężyną. Aby zobrazować siłę sprężyny powiem że jest wykorzystywana do pionowania oparcia, nawet z pozycji prawie leżącej, a krzesło jest przystosowane do użytkowników do 150kg. Oparcie montuje się z wykorzystaniem 4 śrub imbusowych.

Na koniec należy nałożyć plastikowe zaślepki, które przykręca się śrubami krzyżykowymi. Moim zdaniem producent powinien pokryć te śruby czarną powłoką, tak aby wtapiały się w zaślepki, ale chyba się czepiam.

Na koniec wystarczy założyć poduszki i gotowe.

Relacja z Dotnetos – .Net performance world

Piątego listopada 2018 w Hotelu „Airport Hotel Okęcie” w Warszawie odbyła się konferencja Dotnetos – .Net performance world do udziału w niej skłoniły mnie dwa czynniki: fakt że są prelegenci prze-kozakami .Net, oraz to że w tym roku nie uczestniczyłem jeszcze w żadnej innej konferencji. 

<TLDR>

Dużo technicznego mięsna na najwyższym poziomie, w dodatku w bardzo przystępnej cenie. Zdecydowanie polecam wszystkim osobom będącym na pozycjach od mid .Net developer do architekta. Osoby z mniejszym doświadczeniem oraz niezwiązane z technologią .Net mogą się czuć lekko zagubione. W organizacji samej konferencji można jednak trochę poprawić.

</TLDR>

Czytaj dalej Relacja z Dotnetos – .Net performance world

Nasza droga do Reactive Extensions – cz. 2 – Event Aggregator na ratunek

W poprzednim wpisie opisałem problem z wyborem architektury aplikacji przed jakim stanął nasz zespół. W drugiej części opiszę jakie problemy udało się rozwiązać dzięki wzorcowi event aggregator, jakie pozostały nie rozwiązane, a jakie powstały w wyniku jego użycia.

Czytaj dalej Nasza droga do Reactive Extensions – cz. 2 – Event Aggregator na ratunek

Nasza droga do Reactive Extensions – cz. 1 – Wstęp

Artykuł w wersji anglojęzycznej jest dostępny na blogu firmy Grape Up

Jeden z produktów jakie ostatnio rozwijaliśmy w naszym zespole, jest aplikacją desktopową opartą o rozbudowaną bibliotekę, która dostarczała spójne API do komunikacji, opartej o różne protokoły związane z telekomunikacją, co sprawiało że generowała naprawdę dużo sygnałów.

Czytaj dalej Nasza droga do Reactive Extensions – cz. 1 – Wstęp

Cloud Foundry – notatki – Wstęp

Rozpocząłem właśnie naukę nowej technologii – Cloud Foundry (CF). Aby przybliżyć czym jest CF umieszczam tutaj trochę marketingowego bełkotu. Możesz go pominąć klikając w link.

CF obiecuje, że aplikacje tworzone pod jej kątem mogą być wdrożone i uruchomione na chmurach różnych dostawców, zarówno tych publicznych takich jak: AWS, Azure czy Google Cloud, jak i na rozwiązaniach typu private cloud np. OpenStack czy nawet maszyna wirtualna virtual-box.

Czytaj dalej Cloud Foundry – notatki – Wstęp