using Novell.Directory.Ldap; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Berufsschule_HAM.Models; using System.Text.Json; namespace Berufsschule_HAM.Services; public class LdapService : IDisposable { private readonly LdapOptions _opts; private readonly LdapConnection _conn; private ILogger _logger; public LdapService(IOptions options, ILogger logger) { _opts = options.Value; _conn = new LdapConnection { SecureSocketLayer = _opts.UseSsl }; _logger = logger; ConnectAndBind(); } private void ConnectAndBind() { if (!_conn.Connected) { Console.WriteLine(_opts.Host); Console.WriteLine(_opts.Port); try { _conn.Connect(_opts.Host, _opts.Port); } catch (SystemException ex) { _logger.LogCritical("Unable to connect to LDAP: {ex.Message}\n{ex.StackTrace}", [ex.Message, ex.StackTrace]); throw; } } _conn.Bind(_opts.BindDn, _opts.BindPassword); } private string AssetsBaseDn => string.IsNullOrEmpty(_opts.AssetsOu) ? _opts.BaseDn : $"{_opts.AssetsOu},{_opts.BaseDn}"; private string LocationsBaseDn => string.IsNullOrEmpty(_opts.LocationsOu) ? _opts.BaseDn : $"{_opts.LocationsOu},{_opts.BaseDn}"; private string UsersBaseDn => string.IsNullOrEmpty(_opts.UsersOu) ? _opts.BaseDn : $"{_opts.UsersOu},{_opts.BaseDn}"; public async Task>> ListLocationsAsync() { return await ListObjectBy(LocationsBaseDn, "(ou=locations)", ["l", "street", "description"]); } public async Task>> ListUsersAsync() { return await ListObjectBy(UsersBaseDn, "", ["cn", "sn", "userPassword"]); //return await ListObjectBy("objectClass=person"); } public async Task>> ListDeviceAsync() { return await ListObjectBy(AssetsBaseDn, "(objectClass=device)", ["CN", "description", "l", "owner", "serialNumber"]); } public void CreateUser(LdapAttributeSet attributeSet) { CreateObject(UsersBaseDn, attributeSet); } public void CreateAsset(LdapAttributeSet attributeSet) { CreateObject(AssetsBaseDn, attributeSet); } public void CreateLocation(LdapAttributeSet attributeSet) { CreateObject(LocationsBaseDn, attributeSet); } public async Task>> ListObjectBy(string baseDn, string filter, string[] attributes) { return await Task.Run(() => { ConnectAndBind(); var search = _conn.Search( baseDn, LdapConnection.SCOPE_SUB, $"{filter}", attributes, false); var list = new List>(); while (search.hasMore()) { try { var e = search.next(); var attributeSet = e.getAttributeSet().ToArray(); if (attributeSet.Length == 0) { continue; } Dictionary attributeMap = []; foreach (LdapAttribute attribute in attributeSet.Cast()) { attributeMap[attribute.Name] = attribute.StringValue; } list.Add(attributeMap); } catch (LdapException) { } } return list; }); } public void DeleteObjectByDn(string dn) { _conn.Delete(dn); } public void CreateObject(string dn, LdapAttributeSet attributeSet) { LdapEntry ldapEntry = new(dn, attributeSet); _conn.Add(ldapEntry); } public void Dispose() { if (_conn != null && _conn.Connected) { _conn.Disconnect(); } } }