Classify SGU accounts into AD role groups
This commit is contained in:
@@ -21,4 +21,5 @@ internal static class BrokerEventIds
|
||||
internal static readonly EventId DirectorySynchronizationFailure = new(1300, nameof(DirectorySynchronizationFailure));
|
||||
internal static readonly EventId DirectoryOptionalMetadataFailure = new(1301, nameof(DirectoryOptionalMetadataFailure));
|
||||
internal static readonly EventId DirectoryGroupMembershipFailure = new(1302, nameof(DirectoryGroupMembershipFailure));
|
||||
internal static readonly EventId DirectoryRoleGroupMembershipAdded = new(1303, nameof(DirectoryRoleGroupMembershipAdded));
|
||||
}
|
||||
|
||||
@@ -87,6 +87,14 @@ public sealed class BrokerOptions
|
||||
{
|
||||
throw new InvalidOperationException($"The OU mapping for {role} must be beneath BaseDn.");
|
||||
}
|
||||
|
||||
string groupDn = Directory.GetGroupDn(role);
|
||||
if (string.IsNullOrWhiteSpace(groupDn) ||
|
||||
!groupDn.StartsWith("CN=", StringComparison.OrdinalIgnoreCase) ||
|
||||
!groupDn.EndsWith($",{Directory.BaseDn}", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException($"The security-group mapping for {role} must identify a group beneath BaseDn.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Directory.RemoteDesktopGroupDn) &&
|
||||
@@ -168,6 +176,12 @@ public sealed class ActiveDirectoryOptions
|
||||
|
||||
public string AdministrativeOuDn { get; init; } = "OU=Administrativos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string ProfessorGroupDn { get; init; } = "CN=SGU-Docentes,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string StudentGroupDn { get; init; } = "CN=SGU-Alumnos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string AdministrativeGroupDn { get; init; } = "CN=SGU-Administrativos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx";
|
||||
|
||||
public string RemoteDesktopGroupDn { get; init; } = string.Empty;
|
||||
|
||||
public string DefaultCompany { get; init; } = "La Salle";
|
||||
@@ -181,4 +195,12 @@ public sealed class ActiveDirectoryOptions
|
||||
InstitutionalRole.Administrative => AdministrativeOuDn,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(role), role, null)
|
||||
};
|
||||
|
||||
public string GetGroupDn(InstitutionalRole role) => role switch
|
||||
{
|
||||
InstitutionalRole.Professor => ProfessorGroupDn,
|
||||
InstitutionalRole.Student => StudentGroupDn,
|
||||
InstitutionalRole.Administrative => AdministrativeGroupDn,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(role), role, null)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -109,6 +109,12 @@ public sealed class ActiveDirectorySynchronizer(
|
||||
user.CommitChanges();
|
||||
}
|
||||
|
||||
// Role membership is part of account provisioning, not optional
|
||||
// enrichment. Do it before changing the password so a missing or
|
||||
// inaccessible authorization group cannot leave a newly usable
|
||||
// account without its required classification.
|
||||
EnsureRoleGroupMembership(user, identity);
|
||||
|
||||
// The exact institutional password received by the broker is passed to AD.
|
||||
// It is not derived, transformed, written to disk, or included in logs.
|
||||
user.Invoke("SetPassword", [password]);
|
||||
@@ -195,6 +201,33 @@ public sealed class ActiveDirectorySynchronizer(
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureRoleGroupMembership(DirectoryEntry user, UserIdentity identity)
|
||||
{
|
||||
user.RefreshCache(["distinguishedName"]);
|
||||
string? userDn = Convert.ToString(user.Properties["distinguishedName"].Value);
|
||||
if (string.IsNullOrWhiteSpace(userDn))
|
||||
{
|
||||
throw new InvalidOperationException($"Active Directory did not return a distinguished name for {identity.UserName}.");
|
||||
}
|
||||
|
||||
string groupDn = options.GetGroupDn(identity.Role);
|
||||
using DirectoryEntry group = Bind(groupDn);
|
||||
_ = group.NativeObject;
|
||||
if (group.Properties["member"].Contains(userDn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
group.Properties["member"].Add(userDn);
|
||||
group.CommitChanges();
|
||||
logger.LogInformation(
|
||||
BrokerEventIds.DirectoryRoleGroupMembershipAdded,
|
||||
"Added {InstitutionalUser} with role {Role} to Active Directory security group {GroupDn}.",
|
||||
identity.UserName,
|
||||
identity.Role,
|
||||
groupDn);
|
||||
}
|
||||
|
||||
private void TryEnsureRemoteDesktopGroupMembership(DirectoryEntry user, string institutionalUser)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(options.RemoteDesktopGroupDn))
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
"ProfessorOuDn": "OU=Docentes,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"StudentOuDn": "OU=Alumnos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"AdministrativeOuDn": "OU=Administrativos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"ProfessorGroupDn": "CN=SGU-Docentes,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"StudentGroupDn": "CN=SGU-Alumnos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"AdministrativeGroupDn": "CN=SGU-Administrativos,OU=Usuarios-SGU,DC=lci,DC=lasalle,DC=mx",
|
||||
"RemoteDesktopGroupDn": "",
|
||||
"DefaultCompany": "La Salle",
|
||||
"CreateMissingOus": false
|
||||
|
||||
Reference in New Issue
Block a user