Konfigurace přihlašování uživatelů přes MS Entra

Hlavní stránka / Dokumentace / Příručka administrátora /

Konfigurace přihlašování uživatelů přes MS Entra

NET Genium podporuje přihlašování uživatelů pomocí účtů spravovaných v Microsoft Entra ID (dříve Azure Active Directory). Pro využití této funkcionality je nutné provést ruční konfiguraci v prostředí Microsoft Entra ID.

Konfigurace se skládá ze dvou částí, které na sebe navazují — autorizace vyžaduje autentizaci, obráceně to neplatí.

Autentizace (kapitoly 1 a 2) ověří, kdo uživatel je, a přihlásí ho do NET Genia. Sama o sobě žádné účty nezakládá ani nemění: uživatel musí být v NET Geniu založen předem a oprávnění má nastavená ručně.

Autorizace (kapitola 3) navíc při každém přihlášení převezme z MS Entra role uživatele a podle nich mu v NET Geniu nastaví skupinu oprávnění a uživatelské skupiny. Volitelně umí uživatele podle jeho role také založit při prvním přihlášení (kapitola 3.5) — účty pak nemusí zakládat administrátor ručně a vznikají podle rolí přidělených v MS Entra.

1. Konfigurace Microsoft Entra ID

  • Registrace aplikace „NET Genium“ na webové stránce https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
    • česky: portal.azure.com / Registrace aplikací
    • anglicky: portal.azure.com / App registrations
    • NET Genium jako název aplikace
    • Zjištění ID aplikace (klienta), který je automaticky vytvořen při registraci aplikace
      • česky: ID aplikace (klienta)
      • anglicky: Application (client) ID
    • Nastavení URL NET Genia na hodnotu „https://{url_netgenia}/LoginByMicrosoft.aspx“
      • česky: portal.azure.com / Registrace aplikací / NET Genium / Ověřování / Identifikátory URI pro přesměrování
      • anglicky: portal.azure.com / App registrations / NET Genium / Authentication / Redirect URIs
    • Povolení přístupových tokenů
      • česky: portal.azure.com / Registrace aplikací / NET Genium / Ověřování / Implicitní udělení a hybridní toky / Přístupové tokeny (používané pro implicitní toky)
      • anglicky: portal.azure.com / App registrations / NET Genium / Authentication / Implicit grant and hybrid flows / Access tokens (used for implicit flows)
    • Povolení ID tokenů
      • česky: portal.azure.com / Registrace aplikací / NET Genium / Ověřování / Implicitní udělení a hybridní toky / Tokeny ID (používané pro implicitní a hybridní toky)
      • anglicky: portal.azure.com / App registrations / NET Genium / Authentication / Implicit grant and hybrid flows / ID tokens (used for implicit and hybrid flows)
    • Vytvoření tajného kódu klienta
      • česky: portal.azure.com / Registrace aplikací / NET Genium / Certifikáty a tajné kódy / Nový tajný kód klienta
      • anglicky: portal.azure.com / App registrations / NET Genium / Certificates & secrets / New client secret
    • Nastavení oprávnění API pro Microsoft Graph
      • česky: portal.azure.com / Registrace aplikací / NET Genium / Oprávnění rozhraní API / Přidat oprávnění / Microsoft Graph
      • anglicky: portal.azure.com / App registrations / NET Genium / API permissions / Add a permission / Microsoft Graph
      • Název rozhraní API „Microsoft Graph – User.Read“, typ „Delegováno“
      • Pro samotné přihlášení uživatelů toto oprávnění stačí; převzetí rolí z MS Entra popisuje kapitola 3

Obrázek.png

2. Konfigurace NET Genia

  • Vytvoření konfiguračního souboru „NETGenium\Config\MicrosoftOAuth.json“
    • Obsah souboru nastavit na: „{"web":{"client_id":" ID aplikace (klienta) ","auth_uri":"https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize","token_uri":"https://login.microsoftonline.com/organizations/oauth2/v2.0/token","client_secret":"tajný kód klienta"}}“
  • Vytvoření prázdného souboru „NETGenium\Config\LoginByMicrosoft.txt“
    • Jeho existence zapíná volbu přihlášení přes Microsoft na přihlašovací stránce; bez něj se přihlašovací tlačítko nenabídne, i když je konfigurační soubor „MicrosoftOAuth.json“ vyplněný
    • Obsah souboru může nést nepovinné parametry autorizace, viz kapitola 3.5

3. Autorizace — převzetí rolí z MS Entra

Vyhodnocení rolí není součástí NET Genia. NET Genium při každém přihlášení zavolá externí funkci „NETGenium.OnBeforeLogin“ a vlastní práci s rolemi nechá na ní:

  • NET Genia postavená na produktu ERP mají hotovou implementaci k dispozici v knihovně „ERP.dll“ — stačí ji zapojit do projektu „ngef“ (kapitola 3.4) a nastavit skupiny oprávnění (kapitola 3.3).
  • Ostatní NET Genia si autorizaci implementují sama. Klíčové pasáže ze zdrojových kódů knihovny ERP, ze kterých lze vyjít, jsou v kapitole 3.6.

Aby se autorizace vůbec provedla, musí platit současně všechny tyto předpoklady:

  • V souboru „ngef.cs“ projektu „ngef“ je zaregistrovaná externí funkce „NETGenium.OnBeforeLogin“ (kapitola 3.4)
  • U NET Genií postavených na produktu ERP je v adresáři „NETGenium\bin“ vedle knihovny „ngef.dll“ také knihovna „ERP.dll“
  • Je vytvořen konfigurační soubor „NETGenium\Config\LoginByMicrosoft.txt“ (kapitola 2)
  • Editační formulář „Skupina oprávnění“ má ovládací prvek „ng_memberof“ a editační formulář „Uživatel“ ovládací prvek „ng_originalnirole“ (kapitola 3.3)
  • Alespoň jedna skupina oprávnění má vyplněné pole „Member of“ (kapitola 3.3)
  • Uživatel je v NET Geniu založen, nebo je zapnuté automatické zakládání uživatelů (kapitola 3.5)

Nesplnění prvního předpokladu se pozná jedině tím, že se u uživatele po přihlášení nic nezmění. NET Genium volá externí funkci při každém přihlášení, ale její návratovou hodnotu nevyhodnocuje — chybějící registrace proto neskončí chybou ani záznamem v logu.

3.1. Jak autorizace probíhá

Po úspěšném ověření uživatele u Microsoftu a ještě před samotným přihlášením do NET Genia zavolá NET Genium externí funkci „NETGenium.OnBeforeLogin“ a předá jí e-mail uživatele přijatý v tokenu. Implementace v knihovně ERP:

  • Načte skupiny oprávnění, které mají vyplněné pole „Member of“ (sloupec „ng_memberof“ tabulky „srightsgroups“). Nemá-li ho vyplněné ani jedna skupina oprávnění, autorizace se neprovede a oprávnění zůstávají nastavená ručně v NET Geniu.
  • Z tokenu přijatého od Microsoftu vezme role uživatele — položky „roles“ (aplikační role) a „GroupsName“.
  • Pouze tehdy, není-li v tokenu žádná role, zeptá se na skupiny uživatele služby Microsoft Graph na adrese „https://graph.microsoft.com/v1.0/me/transitiveMemberOf“ a použije zobrazované názvy vrácených skupin.
  • Každou nalezenou roli porovná na přesnou shodu celého řetězce, včetně velikosti písmen, s polem „Member of“ každé skupiny oprávnění.
  • Vyhledá uživatele podle e-mailu ve sloupci „email“ tabulky „susers“. Uživatele, který v NET Geniu neexistuje, založí pouze tehdy, je-li zapnuté automatické zakládání (kapitola 3.5); jinak přihlášení proběhne bez jakékoli změny.
  • Nalezenému uživateli nastaví:
    • Skupinu oprávnění — a to pouze tehdy, odpovídá-li rolím právě jedna skupina oprávnění. Neodpovídá-li žádná, nebo odpovídají-li dvě a více, skupina oprávnění se vyprázdní.
    • Uživatelské skupiny — přepíše je uživatelskými skupinami všech odpovídajících skupin oprávnění.
    • Originální role (sloupec „ng_originalnirole“ tabulky „susers“) — seznam rolí přijatých z MS Entra oddělený čárkami.

Nové nastavení se projeví vždy až při dalším přihlášení uživatele — změna role v MS Entra se do právě běžící relace nepromítne.

Upozornění: při přepisu uživatelských skupin se uživateli zároveň smažou jeho oblíbené položky a rozložení portletů na hlavní stránce. Ještě v průběhu téhož přihlášení pak NET Genium uživateli, který žádné oblíbené položky ani portlety nemá, převezme výchozí nastavení z účtu Administrator (uživatel s ID 1) — hlavní stránka tedy nezůstane prázdná, uživatel ale přijde o vlastní úpravy. Nenajde-li se pro uživatele žádná role, ztratí navíc všechny uživatelské skupiny i skupinu oprávnění. Autorizaci proto zkoušejte nejdříve na testovacím účtu.

3.2. Aplikační role v MS Entra

Doporučeným způsobem je použít aplikační role registrované aplikace NET Genium. Role se pak předá přímo v tokenu a NET Genium se službou Microsoft Graph vůbec nekomunikuje — není proto potřeba žádné další oprávnění nad rámec „Microsoft Graph – User.Read“ z kapitoly 1.

  • Vytvoření aplikační role
    • česky: portal.azure.com / Registrace aplikací / NET Genium / Role aplikace / Vytvořit roli aplikace
    • anglicky: portal.azure.com / App registrations / NET Genium / App roles / Create app role
    • Hodnota role (anglicky Value) je text, který se objeví v tokenu a který se porovnává s polem „Member of“ skupiny oprávnění v NET Geniu — nikoli zobrazovaný název role
    • Povolené typy členů (anglicky Allowed member types) nastavit na „Uživatelé nebo skupiny“ (anglicky „Users/Groups“)
  • Přiřazení uživatelů nebo skupin k roli
    • česky: portal.azure.com / Podnikové aplikace / NET Genium / Uživatelé a skupiny
    • anglicky: portal.azure.com / Enterprise applications / NET Genium / Users and groups

Alternativa, kterou nedoporučujeme — načtení skupin ze služby Microsoft Graph. Použije se automaticky tehdy, když v tokenu žádná role není, a vyžaduje:

  • delegované oprávnění „GroupMember.Read.All“ (nebo „Directory.Read.All“) se souhlasem správce
    • česky: portal.azure.com / Registrace aplikací / NET Genium / Oprávnění rozhraní API
    • anglicky: portal.azure.com / App registrations / NET Genium / API permissions
  • rozšíření rozsahu oprávnění v konfiguračním souboru „MicrosoftOAuth.json“ — do objektu „web“ se doplní položka „scope“, například „"scope":"openid email profile GroupMember.Read.All"“; není-li položka uvedena, použije NET Genium rozsah „openid email profile“

Nevýhodou této varianty je, že se porovnávají všechny skupiny, ve kterých je uživatel členem, včetně nepřímého členství — tedy typicky desítky skupin, které s aplikací nijak nesouvisejí. Aplikační role jsou naproti tomu vytvořené přímo pro tuto aplikaci.

3.3. Skupiny oprávnění v NET Geniu

  • Do editačního formuláře „Skupina oprávnění“ doplnit textový ovládací prvek s identifikátorem „ng_memberof“ (například s názvem „Member of“)
  • Do editačního formuláře „Uživatel“ doplnit textový ovládací prvek s identifikátorem „ng_originalnirole“ (například s názvem „Originální role“) — do něj se zapisují role přijaté z MS Entra
  • U každé skupiny oprávnění, která má odpovídat některé roli z MS Entra, vyplnit do pole „Member of“ hodnotu aplikační role; u varianty se službou Microsoft Graph zobrazovaný název skupiny
  • Skupinám oprávnění přiřadit uživatelské skupiny — právě ty se uživateli při přihlášení nastaví

Oba ovládací prvky musí existovat, jinak autorizace skončí chybou. Hodnota v poli „Member of“ musí souhlasit přesně, včetně velikosti písmen a mezer, a pole musí být dost dlouhé na to, aby se do něj celá hodnota role vešla.

3.4. Externí funkce NETGenium.OnBeforeLogin

NET Genia postavená na produktu ERP mají hotovou implementaci v knihovně „ERP.dll“ a zapojí ji takto:

  • Do projektu „ngef“ přidat referenci na knihovnu „ERP.dll“
  • Do souboru „ngef.cs“ zaregistrovat volání:
case "NETGenium.OnBeforeLogin": ERP.Login.OnBeforeLogin(args, conn); return "";
  • Zkompilovanou knihovnu „ngef.dll“ i knihovnu „ERP.dll“ nahrát do adresáře „NETGenium\bin“ — nahrání nové knihovny automaticky restartuje webovou aplikaci

Bez této registrace autorizace neproběhne. Přihlášení se chová jako v kapitolách 1 a 2 a oprávnění uživatele se nezmění.

3.5. Automatické zakládání uživatelů

Ve výchozím stavu se uživatel, který v NET Geniu neexistuje, nezakládá — jeho přihlášení proběhne bez jakékoli změny a účet musí založit administrátor.

Zakládání se zapíná parametrem v konfiguračním souboru „NETGenium\Config\LoginByMicrosoft.txt“. Na samostatný řádek se zapíše:

CreateUsers

Soubor může obsahovat i více parametrů, vždy jeden na řádek; na velikosti písmen nezáleží a prázdné řádky se ignorují.

Je-li parametr zapnutý, založí se uživatel při prvním přihlášení, a to pouze tehdy, odpovídá-li některé jeho roli alespoň jedna skupina oprávnění. Bez této podmínky by účet v NET Geniu získal každý, kdo se dokáže přihlásit v tenantu MS Entra, i když mu tam nikdo žádnou roli nepřidělil.

Novému uživateli se vyplní:

  • Celé jméno, Jméno a Příjmení — rozpadem položky „name“ z tokenu; není-li jméno dvouslovné, uloží se celé do pole „Příjmení“
  • Přihlašovací jméno — odvozené z příjmení a prvního písmene jména; shoduje-li se s existujícím uživatelem, doplní se pořadové číslo
  • Email — e-mail přijatý z MS Entra
  • Skupina oprávnění, uživatelské skupiny a Originální role — podle rolí z MS Entra, stejně jako u existujícího uživatele

E-mail se záměrně nezkracuje. Je-li pole „Email“ v NET Geniu kratší než e-mail přijatý z MS Entra, skončí zakládání chybou zapsanou do logu (kapitola 3.8) — zkrácený e-mail by uživatele při příštím přihlášení nenašel a účet by vznikal znovu při každém přihlášení.

3.6. Vlastní implementace autorizace

NET Genia, která nejsou postavená na produktu ERP, knihovnu „ERP.dll“ k dispozici nemají a autorizaci si implementují sama — jako vlastní externí funkci zaregistrovanou pod klíčem „NETGenium.OnBeforeLogin“ způsobem popsaným v kapitole 3.4. Následující pasáže ze zdrojových kódů knihovny ERP slouží jako výchozí bod; předpokládají jmenné prostory „NETGenium“, „System.Collections.Generic“, „System.Data“ a „System.Security.Claims“.

Vstupní bod — načtení skupin oprávnění, vyhodnocení rolí z tokenu a zápis k uživateli:

public static void OnBeforeLogin(string[] args, DbConnection conn)
{
string loginby = args[0], s;
if (loginby.Length == 0 || conn.HttpContext.Session["microsoft_access_token"] == null)
{
return;
}

DataTable srightsgroups = Data.Get("SELECT id, ng_memberof FROM srightsgroups WHERE NOT ng_memberof = ''", conn);
if (srightsgroups.Rows.Count == 0)
{
return; // Žádná skupina oprávnění není namapovaná na roli - autorizace zůstává na NET Geniu
}

List<int> rightsgroups = new List<int>(), usergroups = new List<int>();
List<string> roles = new List<string>();
int rightsgroup = 0;

if (conn.HttpContext.Session[s = "microsoft_claims"] != null)
foreach (Claim claim in (Claim[])conn.HttpContext.Session[s])
if (claim.Type == "roles")
{
MatchGroups(s = claim.Value, rightsgroups, usergroups, srightsgroups, conn);
roles.Add(s);
}

if (rightsgroups.Count == 1)
{
rightsgroup = rightsgroups[0];
}

DbRow user = new DbRow("SELECT id, rightsgroup, ng_originalnirole FROM susers WHERE email = " + conn.Format(loginby), conn);
if (user.Read())
using (DbCommand cmd = new DbCommand(conn))
{
UpdateUser(user, usergroups, rightsgroup, string.Join(", ", roles.ToArray()), cmd, conn);
}
}

Porovnání role se skupinami oprávnění a dohledání jejich uživatelských skupin:

private static void MatchGroups(string memberOf, List<int> rightsgroups, List<int> usergroups, DataTable srightsgroups, DbConnection conn)
{
int n;

foreach (DataRow row in srightsgroups.Rows)
if (row["ng_memberof"].ToString() == memberOf)
{
if (!rightsgroups.Contains(n = (int)row["id"]))
{
rightsgroups.Add(n);
}

foreach (int usergroup in Data.GroupsInRightsGroup(n, conn))
if (!usergroups.Contains(usergroup))
{
usergroups.Add(usergroup);
}
}
}

Zápis skupiny oprávnění a uživatelských skupin k uživateli. Knihovna ERP maže spolu s uživatelskými skupinami i oblíbené položky a rozložení portletů daného uživatele:

private static void UpdateUser(DbRow user, List<int> usergroups, int rightsgroup, string memberOf, DbCommand cmd, DbConnection conn)
{
int userid = (int)user["id"];

if (Parser.ToInt32(user["rightsgroup"]) != rightsgroup || user["ng_originalnirole"].ToString() != memberOf)
{
DataSaverSynchro ds = new DataSaverSynchro("susers", userid, conn);
ds.Add("rightsgroup", rightsgroup);
ds.Add("ng_originalnirole", memberOf);
ds.Save(cmd);
}

if (memberOf == "" || Sql.Ids("SELECT groupid FROM susers_rights WHERE userid = " + userid + " ORDER BY id", conn) != Sql.Ids(usergroups.ToArray()))
{
foreach (string table in new string[] { "sfavorites", "sportlets", "susers_rights" })
{
cmd.CommandText = "DELETE FROM " + table + " WHERE userid = " + userid;
cmd.ExecuteNonQuery();
}

foreach (int usergroup in usergroups)
{
DataSaver ds = new DataSaver("susers_rights", 0, cmd);
ds.Add("userid", userid);
ds.Add("groupid", usergroup);
ds.Execute();
}
}
}

Knihovna ERP nad rámec těchto pasáží řeší ještě načtení skupin ze služby Microsoft Graph (kapitola 3.2), automatické zakládání uživatelů (kapitola 3.5), přihlašování přes Active Directory a zápis do logu (kapitola 3.8).

3.7. Otestování autorizace

  1. V MS Entra přiřadit testovacímu uživateli právě jednu aplikační roli.
  2. V NET Geniu ověřit, že existuje uživatel se stejným e-mailem a že některá skupina oprávnění má v poli „Member of“ hodnotu té role.
  3. Přihlásit se testovacím uživatelem přes Microsoft.
  4. V NET Geniu otevřít záznam uživatele (Nastavení / Uživatelé) a zkontrolovat: #* pole „Skupina oprávnění“ odpovídá roli z MS Entra #* pole „Originální role“ obsahuje hodnotu role přijaté z MS Entra #* uživatelské skupiny odpovídají uživatelským skupinám dané skupiny oprávnění
  5. Změnit uživateli roli v MS Entra, znovu se přihlásit a ověřit, že se nastavení v NET Geniu změnilo.

Zůstane-li pole „Originální role“ po přihlášení prázdné, nenašla se žádná role — postupovat podle kapitoly 3.8.

3.8. Ladění autorizace

  • Zapnout logování „Na disk“ nebo „Do databáze a na disk“
  • Vyzkoušet přihlášení
  • Analyzovat obsah logového souboru „NETGenium\Logs\Anonymous\{yyyy-MM-dd}\loginbymicrosoft.log“ — do téhož souboru zapisuje jak přihlášení, tak vyhodnocení rolí

Co v logovém souboru hledat:

  • Výpis položek tokenu ve tvaru „název: hodnota“. Každá aplikační role se vypíše jako samostatný řádek „roles: hodnota role“. Chybějí-li řádky „roles“, role se v tokenu vůbec nepřenesla — zkontrolovat v MS Entra, že je role uživateli přiřazena (Podnikové aplikace / NET Genium / Uživatelé a skupiny).
  • Řádek „OnBeforeLogin: no role found, claim types in session“ — zapíše se pokaždé, když se nenašla žádná role, a vypíše, jaké typy položek token doopravdy obsahoval. Hodnota „none“ znamená, že z přihlášení nedorazily žádné položky.
  • Řádky s adresou „https://graph.microsoft.com/v1.0/me/transitiveMemberOf“ a s odpovědí této služby — objeví se jen u varianty bez aplikačních rolí. Text „Uploader.UploadJSon(…) ERROR“ znamená, že volání selhalo, typicky kvůli chybějícímu oprávnění nebo souhlasu správce.
  • Chyby samotné funkce se zapisují ve tvaru „OnBeforeLogin(e-mail)“ do denního logového souboru „NETGenium\Logs\{yyyy-MM-dd}.log“ na úrovni „Error“.

Nejčastější situace:

Projev Příčina
Role je v logu, ale uživatel nemá skupinu oprávnění Pole „Member of“ neodpovídá přesně hodnotě role — překlep, jiná velikost písmen, mezera navíc, zobrazovaný název role místo její hodnoty, nebo příliš krátké pole „Member of“
Uživatel má uživatelské skupiny, ale prázdnou skupinu oprávnění Rolím uživatele odpovídají dvě a více skupin oprávnění; přiřadit uživateli jedinou roli
Role je v logu, ale u uživatele se nezměnilo nic E-mail v tokenu neodpovídá poli „Email“ uživatele v NET Geniu, nebo v projektu není zaregistrována externí funkce „NETGenium.OnBeforeLogin“ (kapitola 3.4)
Uživatel se nezaložil, přestože je zapnutý parametr CreateUsers Žádné jeho roli neodpovídá skupina oprávnění, nebo je pole „Email“ kratší než e-mail z MS Entra — pak je v denním logu chyba „OnBeforeLogin(e-mail)“
Uživatel přišel o všechny uživatelské skupiny Nenašla se žádná role — postupovat podle předchozích bodů této kapitoly
Nastavení uživatele se nemění a žádná skupina oprávnění nemá vyplněné pole „Member of“ Autorizace je záměrně vypnutá a oprávnění zůstávají nastavená ručně v NET Geniu

4. Postup při ladění chyb nebo v případě nefunkčního přihlašování

4.1. Obecné

  • Zapnout logování „Na disk“ nebo „Do databáze a na disk“
  • Vyzkoušet přihlášení
  • Analyzovat obsah logového souboru „NETGenium\Logs\Anonymous\{yyyy-MM-dd}\loginbymicrosoft.log“
  • Podle typu chyby popsané v logovém souboru „loginbymicrosoft.log“
    • Změnit obsah konfiguračního souboru „MicrosoftOAuth.json“
    • Změnit nastavení v Azure (typicky vypršení platnosti client_secret)

4.2. Response status code does not indicate success: 401 (Unauthorized)

  • Vyhledat pokus o přihlášení v logovém souboru „Auth.log“ podle uživatelského účtu a data a času přihlášení.
  • Pokud se v souboru „Auth.log“ záznam pokusu o přihlášení nenachází, nedošlo k úspěšné autentizaci uživatele na webových stránkách společnosti Microsoft. V takovém případě je nutné situaci řešit s firmou, která Microsoft Entra ID konfiguruje, aby s uživatelem krok po kroku proces přihlášení vyzkoušela.
  • Pokud v souboru „Auth.log“ záznam pokusu o přihlášení existuje, postupovat podle chybového hlášení uvedeného v logu.

4.3. Sorry, but we're having trouble with signing you in

  • Ověřit, že jsou v konfiguraci MS Entra zadány všechny varianty přesměrovacích endpointů (s www i bez www).
  • Zkontrolovat přesnou shodu URL adres včetně velikosti písmen.
  • Pokud se v souboru „Auth.log“ záznam pokusu o přihlášení nenachází, nedošlo k úspěšné autentizaci uživatele na webových stránkách společnosti Microsoft. V takovém případě je nutné situaci řešit s firmou, která Microsoft Entra ID konfiguruje, aby s uživatelem krok po kroku proces přihlášení vyzkoušela.