Configuring user login via MS Entra

Home / Documentation / Administrator guide /

Configuring user login via MS Entra

NET Genium supports user login using accounts managed in Microsoft Entra ID (formerly Azure Active Directory). To use this functionality, manual configuration in the Microsoft Entra ID environment is required.

The configuration consists of two parts that build on each other — authorization requires authentication, but not the other way round.

Authentication (chapters 1 and 2) verifies who the user is and signs them in to NET Genium. On its own it neither creates nor changes any accounts: the user must already exist in NET Genium and their rights are set manually.

Authorization (chapter 3) additionally takes the user's roles over from MS Entra on every login and uses them to set the user's rights group and user groups in NET Genium. Optionally it can also create the user on first login according to their role (chapter 3.5), so that accounts do not have to be created manually by an administrator and come into existence according to the roles assigned in MS Entra.

1. Microsoft Entra ID configuration

  • Application registration “NET Genium” at https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
    • portal.azure.com / App registrations
    • NET Genium as the application name
    • Finding Application (client) ID which is automatically created when the application is registered
      • Application (client) ID
    • Setting NET Genium URL to “https://{netgenium_url}/LoginByMicrosoft.aspx”
      • portal.azure.com / App registrations / NET Genium / Authentication / Redirect URIs
    • Enabling access tokens
      • portal.azure.com / App registrations / NET Genium / Authentication / Implicit grant and hybrid flows / Access tokens (used for implicit flows)
    • Enabling ID tokens
      • portal.azure.com / App registrations / NET Genium / Authentication / Implicit grant and hybrid flows / ID tokens (used for implicit and hybrid flows)
    • Creating a client secret
      • portal.azure.com / App registrations / NET Genium / Certificates & secrets / New client secret
    • Setting API permissions for Microsoft Graph
      • portal.azure.com / App registrations / NET Genium / API permissions / Add a permission / Microsoft Graph
      • API name “Microsoft Graph – User.Read”, type “Delegated”
      • This permission is sufficient for signing users in; taking roles over from MS Entra is described in chapter 3

Obrázek.png

2. NET Genium configuration

  • Create a configuration file “NETGenium\Config\MicrosoftOAuth.json ”
    • Set the contents of the file to: “{"web":{"client_id":"Application (client) ID ","auth_uri":"https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize","token_uri":"https://login.microsoftonline.com/organizations/oauth2/v2.0/token","client_secret":"client secret code"}}”
  • Create an empty file “NETGenium\Config\LoginByMicrosoft.txt”
    • Its existence enables the Microsoft sign-in option on the login page; without it the sign-in button is not offered even when the “MicrosoftOAuth.json” configuration file is filled in
    • The contents of the file may carry optional authorization parameters, see chapter 3.5

3. Authorization — taking roles over from MS Entra

Evaluating the roles is not part of NET Genium. On every login NET Genium calls the external function “NETGenium.OnBeforeLogin” and leaves the work with the roles to it:

  • NET Genium instances based on the ERP product have a ready-made implementation available in the “ERP.dll” library — it is enough to plug it into the “ngef” project (chapter 3.4) and to set up the rights groups (chapter 3.3).
  • All other NET Genium instances implement the authorization themselves. Key passages from the source code of the ERP library that can be used as a starting point are in chapter 3.6.

For the authorization to run at all, all of the following prerequisites must be met at the same time:

  • The external function “NETGenium.OnBeforeLogin” is registered in the “ngef.cs” file of the “ngef” project (chapter 3.4)
  • On NET Genium instances based on the ERP product, the “ERP.dll” library is placed in the “NETGenium\bin” directory next to the “ngef.dll” library
  • The configuration file “NETGenium\Config\LoginByMicrosoft.txt” has been created (chapter 2)
  • The “Rights group” edit form has a control named “ng_memberof” and the “User” edit form has a control named “ng_originalnirole” (chapter 3.3)
  • At least one rights group has the “Member of” field filled in (chapter 3.3)
  • The user exists in NET Genium, or automatic user creation is enabled (chapter 3.5)

The only way to notice that the first prerequisite is not met is that nothing changes for the user after login. NET Genium calls the external function on every login but does not evaluate its return value — a missing registration therefore ends neither with an error nor with an entry in the log.

3.1. How the authorization works

After the user has been successfully verified by Microsoft and before the actual login to NET Genium, NET Genium calls the external function “NETGenium.OnBeforeLogin” and passes it the user's e-mail received in the token. The implementation in the ERP library:

  • Loads the rights groups that have the Member of field filled in (the “ng_memberof” column of the “srightsgroups” table). If no rights group has it filled in, the authorization is not performed and the rights stay set manually in NET Genium.
  • Takes the user's roles from the token received from Microsoft — the “roles” (app roles) and “GroupsName” items.
  • Only if there is no role in the token, it asks the Microsoft Graph service for the user's groups at “https://graph.microsoft.com/v1.0/me/transitiveMemberOf” and uses the display names of the returned groups.
  • Compares each role found against the “Member of” field of every rights group for an exact match of the whole string, including letter case.
  • Looks the user up by e-mail in the “email” column of the “susers” table. A user who does not exist in NET Genium is created only if automatic user creation is enabled (chapter 3.5); otherwise the login runs without any change.
  • For the user found it sets:
    • The rights group — but only if exactly one rights group matches the roles. If none matches, or if two or more match, the rights group is cleared.
    • The user groups — they are overwritten with the user groups of all matching rights groups.
    • The original role (the “ng_originalnirole” column of the “susers” table) — the list of roles received from MS Entra, separated by commas.

The new setting always takes effect on the user's next login — a role change in MS Entra is not reflected in a session that is already running.

Warning: when the user groups are overwritten, the user's favourite items and portlet layout on the main page are deleted as well. Later in the very same login, NET Genium then copies the default settings from the Administrator account (the user with ID 1) to a user who has no favourite items and no portlets — so the main page does not stay empty, but the user loses their own customization. If no role is found for the user, they additionally lose all their user groups and their rights group. Try the authorization on a test account first.

3.2. App roles in MS Entra

The recommended way is to use the app roles of the registered NET Genium application. The role is then passed directly in the token and NET Genium does not communicate with the Microsoft Graph service at all — no permission beyond “Microsoft Graph – User.Read” from chapter 1 is therefore needed.

  • Creating an app role
    • portal.azure.com / App registrations / NET Genium / App roles / Create app role
    • The Value of the role is the text that appears in the token and that is compared against the “Member of” field of a rights group in NET Genium — not the display name of the role
    • Set Allowed member types to “Users/Groups”
  • Assigning users or groups to the role
    • portal.azure.com / Enterprise applications / NET Genium / Users and groups

An alternative we do not recommend — reading the groups from the Microsoft Graph service. It is used automatically when there is no role in the token, and it requires:

  • the delegated permission “GroupMember.Read.All” (or “Directory.Read.All”) with administrator consent
    • portal.azure.com / App registrations / NET Genium / API permissions
  • extending the scope in the “MicrosoftOAuth.json” configuration file — a “scope” item is added to the “web” object, for example “"scope":"openid email profile GroupMember.Read.All"”; if the item is not present, NET Genium uses the scope “openid email profile”

The drawback of this variant is that all groups the user is a member of are compared, including indirect membership — typically dozens of groups that have nothing to do with the application. App roles, on the other hand, are created for this application only.

3.3. Rights groups in NET Genium

  • Add a text control with the identifier “ng_memberof” to the “Rights group” edit form (for example with the name “Member of”)
  • Add a text control with the identifier “ng_originalnirole” to the “User” edit form (for example with the name “Original role”) — the roles received from MS Entra are written into it
  • For every rights group that is to correspond to a role from MS Entra, fill the value of the app role into the “Member of” field; with the Microsoft Graph variant, the display name of the group
  • Assign user groups to the rights groups — these are exactly the groups that are set for the user on login

Both controls must exist, otherwise the authorization ends with an error. The value in the “Member of” field must match exactly, including letter case and spaces, and the field must be long enough to hold the whole value of the role.

3.4. The NETGenium.OnBeforeLogin external function

NET Genium instances based on the ERP product have a ready-made implementation in the “ERP.dll” library and plug it in as follows:

  • Add a reference to the “ERP.dll” library to the “ngef” project
  • Register the call in the “ngef.cs” file:
case "NETGenium.OnBeforeLogin": ERP.Login.OnBeforeLogin(args, conn); return "";
  • Upload both the compiled “ngef.dll” library and the “ERP.dll” library to the “NETGenium\bin” directory — uploading a new library restarts the web application automatically

Without this registration the authorization does not run. The login behaves as in chapters 1 and 2 and the user's rights do not change.

3.5. Automatic user creation

By default a user who does not exist in NET Genium is not created — their login runs without any change and the account has to be created by an administrator.

Creation is enabled by a parameter in the “NETGenium\Config\LoginByMicrosoft.txt” configuration file. The following is written on a line of its own:

CreateUsers

The file may contain more parameters, always one per line; letter case does not matter and empty lines are ignored.

When the parameter is enabled, the user is created on first login, and only if at least one rights group corresponds to one of their roles. Without this condition an account in NET Genium would be granted to anyone able to sign in to the MS Entra tenant, even if nobody assigned them any role there.

The new user gets the following filled in:

  • Full name, first name and surname — by splitting the “name” item from the token; if the name does not consist of two words, the whole of it is stored in the surname field
  • Login name — derived from the surname and the first letter of the first name; if it collides with an existing user, a sequence number is appended
  • E-mail — the e-mail received from MS Entra
  • Rights group, user groups and original role — according to the roles from MS Entra, the same way as for an existing user

The e-mail is deliberately not truncated. If the “Email” field in NET Genium is shorter than the e-mail received from MS Entra, the creation ends with an error written into the log (chapter 3.8) — a truncated e-mail would not find the user on their next login and the account would be created again on every login.

3.6. Implementing the authorization yourself

NET Genium instances that are not based on the ERP product do not have the “ERP.dll” library available and implement the authorization themselves — as their own external function registered under the “NETGenium.OnBeforeLogin” key in the way described in chapter 3.4. The following passages from the source code of the ERP library serve as a starting point; they assume the “NETGenium”, “System.Collections.Generic”, “System.Data” and “System.Security.Claims” namespaces.

The entry point — loading the rights groups, evaluating the roles from the token and writing the result to the user:

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; // No rights group is mapped to a role - the authorization stays with NET Genium
}

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);
}
}

Comparing a role against the rights groups and looking up their user groups:

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);
}
}
}

Writing the rights group and the user groups to the user. Along with the user groups, the ERP library also deletes the favourite items and the portlet layout of that user:

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();
}
}
}

Beyond these passages, the ERP library also handles reading the groups from the Microsoft Graph service (chapter 3.2), automatic user creation (chapter 3.5), login through Active Directory and writing to the log (chapter 3.8).

3.7. Testing the authorization

  1. Assign exactly one app role to a test user in MS Entra.
  2. In NET Genium, verify that a user with the same e-mail exists and that some rights group has the value of that role in its “Member of” field.
  3. Sign in as the test user through Microsoft.
  4. Open the user's record in NET Genium (Settings / Users) and check that: #* the “Rights group” field corresponds to the role from MS Entra #* the “Original role” field contains the value of the role received from MS Entra #* the user groups correspond to the user groups of that rights group
  5. Change the user's role in MS Entra, sign in again and verify that the setting in NET Genium has changed.

If the “Original role” field stays empty after the login, no role was found — proceed according to chapter 3.8.

3.8. Debugging the authorization

  • Enable logging “To disk” or “To database and to disk”
  • Test the login process
  • Analyze the content of the log file “NETGenium\Logs\Anonymous\{yyyy-MM-dd}\loginbymicrosoft.log” — both the login and the evaluation of the roles write into the same file

What to look for in the log file:

  • The list of token items in the form “name: value”. Each app role is written as a separate line “roles: value of the role”. If the “roles” lines are missing, the role was not passed in the token at all — check in MS Entra that the role is assigned to the user (Enterprise applications / NET Genium / Users and groups).
  • The line “OnBeforeLogin: no role found, claim types in session” — it is written whenever no role was found, and it lists which item types the token actually contained. The value “none” means that no items arrived from the login at all.
  • Lines with the address “https://graph.microsoft.com/v1.0/me/transitiveMemberOf” and with the response of that service — they appear only with the variant without app roles. The text “Uploader.UploadJSon(…) ERROR” means that the call failed, typically because of a missing permission or administrator consent.
  • Errors of the function itself are written in the form “OnBeforeLogin(e-mail)” into the daily log file “NETGenium\Logs\{yyyy-MM-dd}.log” at the “Error” level.

The most frequent situations:

Symptom Cause
The role is in the log but the user has no rights group The “Member of” field does not match the value of the role exactly — a typo, different letter case, an extra space, the display name of the role instead of its value, or a “Member of” field that is too short
The user has user groups but an empty rights group Two or more rights groups correspond to the user's roles; assign the user a single role
The role is in the log but nothing changed for the user The e-mail in the token does not match the “Email” field of the user in NET Genium, or the external function “NETGenium.OnBeforeLogin” is not registered in the project (chapter 3.4)
The user was not created even though the CreateUsers parameter is enabled No rights group corresponds to any of their roles, or the “Email” field is shorter than the e-mail from MS Entra — in that case the daily log contains the error “OnBeforeLogin(e-mail)”
The user lost all their user groups No role was found — proceed according to the previous points of this chapter
Nothing changes for the user and no rights group has the “Member of” field filled in The authorization is deliberately switched off and the rights stay set manually in NET Genium

4. Debugging errors or in case of broken login

4.1. General

  • Enable logging “To disk” or “To database and to disk”
  • Test the login process
  • Analyze the content of the log file “NETGenium\Logs\Anonymous\{yyyy-MM-dd}\loginbymicrosoft.log”
  • Proceed according to the type of error described in the “loginbymicrosoft.log” file
    • Change the contents of the configuration file “MicrosoftOAuth.json”
    • Change settings in Azure (typically client_secret expiration)

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

  • Search for the login attempt in the Auth.log log file.
  • Search for the entry by the login date and time and user account.
  • If there is no login entry in the Auth.log file, authentication on the Microsoft service side was not successful. In this case, you need to check the application configuration, client login details and OAuth settings in the service environment.
  • If there is an entry, proceed according to the error message in the log and adjust the configuration in the NetGenium system or in the provider identity settings.

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

  • Verify that all redirect endpoint variants (with www and without www) are specified in the MS Entra configuration.
  • Check the exact match of URL addresses, including case.
  • If no login attempt record is found in the “Auth.log” file, the user authentication on Microsoft’s web services was not successful. In this case, the issue must be resolved with the company responsible for configuring Microsoft Entra ID, which should go through the login process step by step with the user.