diff --git a/Wollmilchsau/Components/Pages/Home.razor b/Wollmilchsau/Components/Pages/Home.razor index 81b9641..0448ba8 100644 --- a/Wollmilchsau/Components/Pages/Home.razor +++ b/Wollmilchsau/Components/Pages/Home.razor @@ -22,6 +22,7 @@ else Classroom Given name Incomplete + Role @@ -33,6 +34,7 @@ else @user.Classroom @user.GivenName @user.Incomplete + @user.Role } @@ -54,11 +56,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(); } diff --git a/Wollmilchsau/Models/LdapUser.cs b/Wollmilchsau/Models/LdapUser.cs index 29a062b..f0cd8ba 100644 --- a/Wollmilchsau/Models/LdapUser.cs +++ b/Wollmilchsau/Models/LdapUser.cs @@ -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); diff --git a/Wollmilchsau/Services/Ldap/LdapOptions.cs b/Wollmilchsau/Services/Ldap/LdapOptions.cs index 5149cbf..31de766 100644 --- a/Wollmilchsau/Services/Ldap/LdapOptions.cs +++ b/Wollmilchsau/Services/Ldap/LdapOptions.cs @@ -24,4 +24,7 @@ public sealed class LdapOptions [Required] public string StudentsRole { get; init; } = string.Empty; + + [Required] + public string TeacherRole { get; init; } = string.Empty; } diff --git a/Wollmilchsau/Services/Ldap/LdapService.cs b/Wollmilchsau/Services/Ldap/LdapService.cs index b34f2bc..5ac56cf 100644 --- a/Wollmilchsau/Services/Ldap/LdapService.cs +++ b/Wollmilchsau/Services/Ldap/LdapService.cs @@ -49,27 +49,30 @@ public sealed class LdapService(IOptions options) : ILdapService private IEnumerable 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() - .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 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) diff --git a/Wollmilchsau/Wollmilchsau.csproj b/Wollmilchsau/Wollmilchsau.csproj index f3840d0..5686669 100644 --- a/Wollmilchsau/Wollmilchsau.csproj +++ b/Wollmilchsau/Wollmilchsau.csproj @@ -14,7 +14,7 @@ - +