diff --git a/docs/20250928 Object attribute specs.md b/docs/20250928 Object attribute specs.md index 1dab42c..07b0f84 100644 --- a/docs/20250928 Object attribute specs.md +++ b/docs/20250928 Object attribute specs.md @@ -2,7 +2,7 @@ ## users - ObjectClass: - - extensibleObject + - inetOrgPerson - person - top - cn = Name diff --git a/src/Berufsschule_HAM.csproj b/src/Berufsschule_HAM.csproj index 0318cad..0989a79 100644 --- a/src/Berufsschule_HAM.csproj +++ b/src/Berufsschule_HAM.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Controllers/HomeController.cs b/src/Controllers/HomeController.cs index 36abf91..156b55d 100644 --- a/src/Controllers/HomeController.cs +++ b/src/Controllers/HomeController.cs @@ -5,6 +5,7 @@ using Berufsschule_HAM.Models; using Novell.Directory.Ldap; using Berufsschule_HAM.Services; +[ApiExplorerSettings(IgnoreApi = true)] [Route("[controller]")] public class HomeController : Controller { diff --git a/src/Controllers/UsersController.cs b/src/Controllers/UsersController.cs index 67e52a8..bd655ca 100644 --- a/src/Controllers/UsersController.cs +++ b/src/Controllers/UsersController.cs @@ -8,7 +8,13 @@ using System.Threading.Tasks; public class UsersController : Controller { private readonly LdapService _ldap; - public UsersController(LdapService ldap) => _ldap = ldap; + private readonly ILogger _logger; + + public UsersController(LdapService ldap, ILogger logger) + { + _ldap = ldap; + _logger = logger; + } [HttpGet("Index")] public async Task>> Index() @@ -35,28 +41,35 @@ public class UsersController : Controller } [HttpGet("Create")] - public async Task Create(string cn, string sn, string userPassword) - { - // return await new Task(() => - // { - try + public bool Create(string cn, string sn, string? title, string? uid, string userPassword, string? description, string jpegPhoto) + { + try + { + jpegPhoto ??= System.IO.File.ReadAllText("wwwroot/user_default.jpeg"); // TODO: cleanup - make this a config setting + uid ??= sn.ToLower() + cn.ToLower(); + title ??= ""; + description ??= "{}"; + LdapAttributeSet attributeSet = new LdapAttributeSet { - LdapAttributeSet attributeSet = []; - attributeSet.Add(new LdapAttribute("objectClass", "organizationalPerson")); - attributeSet.Add(new LdapAttribute("objectClass", "person")); - //attributeSet.Add(new LdapAttribute("ou", "users")); - attributeSet.Add(new LdapAttribute("objectClass", "top")); - attributeSet.Add(new LdapAttribute("cn", cn)); - attributeSet.Add(new LdapAttribute("sn", sn)); - attributeSet.Add(new LdapAttribute("userPassword", userPassword)); - _ldap.CreateUser(attributeSet); - return true; - } - catch (Exception ex) - { - return false; - } - // }); + new LdapAttribute("objectClass", "inetOrgPerson"), + new LdapAttribute("objectClass", "person"), + new LdapAttribute("objectClass", "top"), + new LdapAttribute("cn", cn), + new LdapAttribute("sn", sn), + new LdapAttribute("title", title), + new LdapAttribute("uid", uid), + new LdapAttribute("jpegPhoto", jpegPhoto), + new LdapAttribute("description", description), + new LdapAttribute("userPassword", userPassword) + }; + _ldap.CreateUser(uid, attributeSet); + return true; + } + catch (Exception ex) + { + _logger.LogError("Unable to create user: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]); + return false; + } } } diff --git a/src/Services/LdapService.cs b/src/Services/LdapService.cs index 16f3ef0..f5ebbaf 100644 --- a/src/Services/LdapService.cs +++ b/src/Services/LdapService.cs @@ -19,10 +19,10 @@ public class LdapService : IDisposable _opts = options.Value; _conn = new LdapConnection { SecureSocketLayer = _opts.UseSsl }; _logger = logger; - ConnectAndBind(); + ConnectAndBind().Wait(); } - private void ConnectAndBind() + private async Task ConnectAndBind() { if (!_conn.Connected) { @@ -30,7 +30,7 @@ public class LdapService : IDisposable Console.WriteLine(_opts.Port); try { - _conn.Connect(_opts.Host, _opts.Port); + await _conn.ConnectAsync(_opts.Host, _opts.Port); } catch (SystemException ex) { @@ -38,7 +38,7 @@ public class LdapService : IDisposable throw; } } - _conn.Bind(_opts.BindDn, _opts.BindPassword); + await _conn.BindAsync(_opts.BindDn, _opts.BindPassword); } private string AssetsBaseDn => string.IsNullOrEmpty(_opts.AssetsOu) ? _opts.BaseDn : $"{_opts.AssetsOu},{_opts.BaseDn}"; @@ -52,8 +52,7 @@ public class LdapService : IDisposable public async Task>> ListUsersAsync() { - return await ListObjectBy(UsersBaseDn, "", ["cn", "sn", "userPassword"]); - //return await ListObjectBy("objectClass=person"); + return await ListObjectBy(UsersBaseDn, "", ["cn", "sn", "title", "uid", "jpegPhoto", "userPassword", "description"]); } public async Task>> ListDeviceAsync() @@ -61,9 +60,10 @@ public class LdapService : IDisposable return await ListObjectBy(AssetsBaseDn, "(objectClass=device)", ["CN", "description", "l", "owner", "serialNumber"]); } - public void CreateUser(LdapAttributeSet attributeSet) + public void CreateUser(string uid, LdapAttributeSet attributeSet) { - CreateObject(UsersBaseDn, attributeSet); + string dn = PrependRDN($"uid={uid}", UsersBaseDn); + CreateObject(dn, attributeSet); } public void CreateAsset(LdapAttributeSet attributeSet) @@ -76,27 +76,32 @@ public class LdapService : IDisposable CreateObject(LocationsBaseDn, attributeSet); } + private string PrependRDN(string rdn, string dn) + { + return rdn + "," + dn; + } + public async Task>> ListObjectBy(string baseDn, string filter, string[] attributes) { - return await Task.Run(() => + return await Task.Run(async () => { - ConnectAndBind(); - var search = _conn.Search( + await ConnectAndBind(); + var search = await _conn.SearchAsync( baseDn, - LdapConnection.SCOPE_SUB, + LdapConnection.ScopeSub, $"{filter}", attributes, false); var list = new List>(); - while (search.hasMore()) + while (await search.HasMoreAsync()) { try { - var e = search.next(); - var attributeSet = e.getAttributeSet().ToArray(); - if (attributeSet.Length == 0) { continue; } + var e = await search.NextAsync(); + var attributeSet = e.GetAttributeSet(); + if (attributeSet.Count == 0) { continue; } Dictionary attributeMap = []; - foreach (LdapAttribute attribute in attributeSet.Cast()) + foreach (LdapAttribute attribute in attributeSet) { attributeMap[attribute.Name] = attribute.StringValue; } @@ -108,15 +113,16 @@ public class LdapService : IDisposable }); } - public void DeleteObjectByDn(string dn) + public async void DeleteObjectByDn(string dn) { - _conn.Delete(dn); + await _conn.DeleteAsync(dn); } - public void CreateObject(string dn, LdapAttributeSet attributeSet) + public async void CreateObject(string dn, LdapAttributeSet attributeSet) { + await ConnectAndBind(); LdapEntry ldapEntry = new(dn, attributeSet); - _conn.Add(ldapEntry); + await _conn.AddAsync(ldapEntry); } public void Dispose()