Merge
This commit is contained in:
@@ -28,6 +28,7 @@ else
|
||||
<th>Classroom</th>
|
||||
<th>Given name</th>
|
||||
<th>Incomplete</th>
|
||||
<th>Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -39,6 +40,7 @@ else
|
||||
<td>@user.Classroom</td>
|
||||
<td>@user.GivenName</td>
|
||||
<td>@user.Incomplete</td>
|
||||
<td>@user.Role</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
@@ -56,11 +58,13 @@ else
|
||||
|
||||
private Task DownloadCsvAsync()
|
||||
{
|
||||
var csv = string.Join("\r\n", Users.Select(user => string.Join(';',
|
||||
user.GivenName ?? string.Empty,
|
||||
user.Surname ?? string.Empty,
|
||||
user.Classroom ?? string.Empty,
|
||||
user.Username)));
|
||||
var csv = string.Join("\r\n", users!
|
||||
.Where(user => user.Role == Wollmilchsau.Models.LdapUserRole.Student)
|
||||
.Select(user => string.Join(';',
|
||||
user.GivenName ?? string.Empty,
|
||||
user.Surname ?? string.Empty,
|
||||
user.Classroom ?? string.Empty,
|
||||
user.Username)));
|
||||
|
||||
return JsRuntime.InvokeVoidAsync("downloadTextFile", "ldap-users.csv", csv).AsTask();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
namespace Wollmilchsau.Models;
|
||||
|
||||
public enum LdapUserRole
|
||||
{
|
||||
Student,
|
||||
Teacher
|
||||
}
|
||||
|
||||
public sealed record LdapUser(
|
||||
string Username,
|
||||
string? Surname,
|
||||
string? Classroom,
|
||||
string? GivenName,
|
||||
bool Incomplete);
|
||||
bool Incomplete,
|
||||
LdapUserRole Role);
|
||||
|
||||
@@ -24,4 +24,7 @@ public sealed class LdapOptions
|
||||
|
||||
[Required]
|
||||
public string StudentsRole { get; init; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string TeacherRole { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -49,27 +49,30 @@ public sealed class LdapService(IOptions<LdapOptions> options) : ILdapService
|
||||
private IEnumerable<LdapUser> GetUsers(LdapConnection connection)
|
||||
{
|
||||
var studentRoleDn = BuildDistinguishedName(_options.StudentsRole, _options.RoleBase);
|
||||
var teacherRoleDn = BuildDistinguishedName(_options.TeacherRole, _options.RoleBase);
|
||||
var request = new SearchRequest(
|
||||
BuildDistinguishedName(_options.UserBase),
|
||||
$"(memberOf={EscapeFilterValue(studentRoleDn)})",
|
||||
$"(|(memberOf={EscapeFilterValue(studentRoleDn)})(memberOf={EscapeFilterValue(teacherRoleDn)}))",
|
||||
SearchScope.Subtree,
|
||||
"uid",
|
||||
"sn",
|
||||
"departmentNumber",
|
||||
"givenName");
|
||||
"givenName",
|
||||
"memberOf");
|
||||
var response = (SearchResponse)connection.SendRequest(request);
|
||||
|
||||
return response.Entries
|
||||
.Cast<SearchResultEntry>()
|
||||
.Select(CreateUser);
|
||||
.Select(entry => CreateUser(entry, studentRoleDn, teacherRoleDn));
|
||||
}
|
||||
|
||||
private LdapUser CreateUser(SearchResultEntry entry)
|
||||
private LdapUser CreateUser(SearchResultEntry entry, string studentRoleDn, string teacherRoleDn)
|
||||
{
|
||||
var username = GetFirstAttributeValue(entry, "uid") ?? throw new InvalidOperationException($"LDAP user entry '{entry.DistinguishedName}' is missing uid.");
|
||||
var surname = CapitalizeFirstLetter(GetFirstAttributeValue(entry, "sn"));
|
||||
var classroom = GetFirstAttributeValue(entry, "departmentNumber");
|
||||
var givenName = GetFirstAttributeValue(entry, "givenName");
|
||||
var role = DetermineUserRole(entry, studentRoleDn, teacherRoleDn);
|
||||
|
||||
return new LdapUser(
|
||||
username,
|
||||
@@ -78,7 +81,25 @@ public sealed class LdapService(IOptions<LdapOptions> options) : ILdapService
|
||||
givenName,
|
||||
string.IsNullOrWhiteSpace(surname) ||
|
||||
string.IsNullOrWhiteSpace(classroom) ||
|
||||
string.IsNullOrWhiteSpace(givenName));
|
||||
string.IsNullOrWhiteSpace(givenName),
|
||||
role);
|
||||
}
|
||||
|
||||
private static LdapUserRole DetermineUserRole(SearchResultEntry entry, string studentRoleDn, string teacherRoleDn)
|
||||
{
|
||||
var roles = GetAttributeValues(entry, "memberOf");
|
||||
|
||||
if (roles.Contains(studentRoleDn, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return LdapUserRole.Student;
|
||||
}
|
||||
|
||||
if (roles.Contains(teacherRoleDn, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return LdapUserRole.Teacher;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"LDAP user entry '{entry.DistinguishedName}' is not a member of a supported role.");
|
||||
}
|
||||
|
||||
private string BuildDistinguishedName(params string[] relativeNames)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageReference Include="Hangfire" Version="1.8.24" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.24" />
|
||||
<PackageReference Include="Hangfire.Redis.StackExchange" Version="1.12.0" />
|
||||
<PackageReference Include="Marten.AspNetCore" Version="9.27.0" />
|
||||
<PackageReference Include="Marten.AspNetCore" Version="9.28.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.Graph" Version="6.5.0" />
|
||||
|
||||
Reference in New Issue
Block a user