Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop

This commit is contained in:
jrojas
2026-06-26 09:52:35 +02:00
commit 319fd3dfb0
746 changed files with 106610 additions and 0 deletions
+342
View File
@@ -0,0 +1,342 @@
using adas_core.Authentication.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Exceptions;
using adas_core.Domain.Models.MongoModels;
using adas_core.LdapLogin.Configuration;
using FluentValidation;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Novell.Directory.Ldap;
namespace adas_core.LdapLogin;
public class LdapLoginService : ILoginService
{
private readonly IAuthorityService _authorityService;
private readonly LdapConfig _ldapConfig;
private readonly ILogger<LdapLoginService> _logger;
private readonly Lazy<IUserService> _userService;
public LdapLoginService(
IOptions<LdapConfig> ldapConfig,
IValidator<LdapConfig> validator,
Lazy<IUserService> userService,
IAuthorityService authorityService,
ILogger<LdapLoginService> logger)
{
_userService = userService;
_authorityService = authorityService;
_logger = logger;
_ldapConfig = ldapConfig.Value;
validator.Validate(_ldapConfig, options => options.ThrowOnFailures());
}
public bool AllowPassword => true;
public UserEnum.LoginMethod Method => UserEnum.LoginMethod.Ldap;
public async Task<User> Login(string username, string password)
{
// Check for LDAP config
if (_ldapConfig.Server == null) throw new LoginServicesException("LDAP Config not found");
var conn = new LdapConnection();
try
{
await conn.ConnectAsync(_ldapConfig.Server, _ldapConfig.Port ?? 389);
}
catch (Exception e)
{
_logger.LogError("[LDAP] Error connecting to {server}, port {port}, Exception: {e}", _ldapConfig.Server,
_ldapConfig.Port, e.Message);
throw;
}
if (_ldapConfig.LdapUser != null)
{
_logger.LogInformation("[LDAP] _ldapConfig.LdapUser is enabled with {LdapUser}", _ldapConfig.LdapUser);
await conn.BindAsync(_ldapConfig.LdapUser, _ldapConfig.LdapPassword);
}
else
{
var ldapUser = (!string.IsNullOrEmpty(_ldapConfig.UserDomainName)
? _ldapConfig.UserDomainName + @"\"
: "") + username;
try
{
await conn.BindAsync(ldapUser, password);
}
catch (LdapException e)
{
_logger.LogError("[LDAP] Error binding ldapUser: {LdapUser} and password", ldapUser);
throw new UserNotFoundException(username, e);
}
}
var results = await conn.SearchAsync(
_ldapConfig.SearchBase,
LdapConnection.ScopeSub,
$"({_ldapConfig.UserNameProperty}={username})",
null,
false);
LdapEntry? entry = null;
while (await results.HasMoreAsync())
{
LdapEntry? current = null;
try
{
current = await results.NextAsync();
}
catch (LdapException ex)
{
_logger.LogWarning("[LDAP] Skipping invalid entry: {error}", ex.Message);
continue;
}
if (current != null)
{
entry = current;
break;
}
}
if (entry == null) throw new LoginServicesException("LDAP User not found");
var userEntryLdap = GetUser(entry);
var user = await GetOrCreateUser(userEntryLdap, entry);
_logger.LogInformation("[LDAP] entry is {entry} and user {user}", entry, user);
// user.Authorization.AddRange(GetAuthorities(entry));
conn.Disconnect();
return user ?? throw new LoginServicesException("LDAP User not found");
}
public Task<User> Login(HttpContext context)
{
throw new LoginServicesException("Not implemented");
}
public Task<User> Authenticate(string username, string password)
{
throw new LoginServicesException("Not implemented");
}
public Task<User?> GetById(ObjectId id)
{
throw new LoginServicesException("Not implemented");
}
public Task<User?> GetByEmail(string email)
{
throw new LoginServicesException("Not implemented");
}
public Task<User?> GetByUsername(string username)
{
throw new LoginServicesException("Not implemented");
}
public Task<List<User>> GetAllUsers()
{
throw new LoginServicesException("Not implemented");
}
private async Task<User?> GetOrCreateUser(User userEntryLdap, LdapEntry entry)
{
var userToReturn = (await _userService.Value.GetUserByUserName(userEntryLdap.UserName) ??
await _userService.Value.GetUserByName(userEntryLdap.Name)) ??
await _userService.Value.CreateUser(userEntryLdap);
if (userToReturn == null) return userToReturn;
userToReturn.Authorization = [];
var authorities = await CheckAuthorities(userToReturn, entry);
userToReturn.Authorization.AddRange(authorities);
//foreach (var authorization in userToReturn.Authorization)
//{
// Enum.TryParse<RolesType>(authorization.Rol, out var compareRole);
// if (compareRole == RolesType.Admin) userToReturn.Rol = RolesType.Admin;
//}
return userToReturn;
}
private async Task<List<Authorization>> CheckAuthorities(User user, LdapEntry entry)
{
try
{
var authorizationMap = GetAuthoritiesMap(entry, user);
var authorizationWhiteList = GetAuthoritiesWhiteList(entry, user);
_logger.LogInformation(
"[LDAP] user {user} authorizationMap count is {authorizationMap}, authorizationWhiteList count is {authorizationWhiteList}",
user.UserName, authorizationMap.Count, authorizationWhiteList.Count);
// Primero, creamos un HashSet con los DisplayID de la lista blanca para búsqueda eficiente
var whiteListDisplayIds = new HashSet<string?>(authorizationWhiteList.Select(a => a.DisplayId));
// Filtramos los elementos de authorizationMap que no están en la lista blanca, basándonos en DisplayID
var uniqueMapAuthorizations = authorizationMap.Where(a => !whiteListDisplayIds.Contains(a.DisplayId));
// Finalmente, combinamos los elementos únicos de authorizationMap con los de authorizationWhiteList
var combinedList = authorizationWhiteList.Concat(uniqueMapAuthorizations).ToList();
var userAuthorities = await _authorityService.GetUserAuthorities(user.Id);
foreach (var auth in combinedList)
{
var authFound = userAuthorities.Find(c => c.DisplayId == auth.DisplayId);
if (authFound is { CanUpdate: true })
{
authFound.Rol = auth.Rol;
await _authorityService.updateOne(authFound);
}
else
{
await _authorityService.InsertOne(auth);
}
}
return await _authorityService.GetUserAuthorities(user.Id);
}
catch (Exception e)
{
_logger.LogError("[LDAP] CheckAuthorities for user {user} has exception {ex}", user.UserName, e.Message);
return [];
}
}
private List<Authorization> GetAuthoritiesWhiteList(LdapEntry entry, User user)
{
try
{
var userWhiteList = new List<Authorization>();
var userNameProperty = _ldapConfig.UserNameProperty;
var whiteList = _ldapConfig.WhiteList.FindAll(u =>
(u.Name != null && entry.Dn.Contains(u.Name, StringComparison.CurrentCultureIgnoreCase)) ||
(u.Username != null &&
userNameProperty != null &&
entry.GetAttributeSet().TryGetValue(userNameProperty, out var attr) &&
attr.StringValue != null &&
attr.StringValue.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase))
);
if (whiteList.Count == 0) return userWhiteList;
foreach (var authorityMap in whiteList)
{
if (!Enum.TryParse<PermissionEnum.RolesType>(authorityMap.Rol, out _))
continue;
userWhiteList.Add(new Authorization
{
UserId = user.Id,
DisplayId = authorityMap.DisplayId,
Rol = authorityMap.Rol
});
}
return userWhiteList;
}
catch (Exception e)
{
_logger.LogError("[LDAP] GetAuthoritiesWhiteList for user {user} has exception {ex}", user.UserName,
e.Message);
return [];
}
}
private User GetUser(LdapEntry ldapEntry)
{
var attributes = ldapEntry.GetAttributeSet();
var user = new User();
// UserName
if (!string.IsNullOrWhiteSpace(_ldapConfig.UserNameProperty) &&
attributes.TryGetValue(_ldapConfig.UserNameProperty, out var userAttr) &&
userAttr?.StringValue != null)
{
user.UserName = userAttr.StringValue;
}
else
{
user.UserName = "";
}
_logger.LogInformation("[LDAP] GetUser UserName is {UserName} ", user.UserName);
// First name
if (!string.IsNullOrWhiteSpace(_ldapConfig.FirstNameProperty) &&
attributes.TryGetValue(_ldapConfig.FirstNameProperty, out var firstNameAttr) &&
firstNameAttr?.StringValue != null)
{
user.Name = firstNameAttr.StringValue;
}
// Last name
if (!string.IsNullOrWhiteSpace(_ldapConfig.LastNameProperty) &&
attributes.TryGetValue(_ldapConfig.LastNameProperty, out var lastNameAttr) &&
lastNameAttr?.StringValue != null)
{
user.Name = string.IsNullOrEmpty(user.Name)
? lastNameAttr.StringValue
: $"{user.Name} {lastNameAttr.StringValue}";
}
return user;
}
private List<Authorization> GetAuthoritiesMap(LdapEntry ldapEntry, User user)
{
try
{
var authorities = new List<Authorization>();
if (!_ldapConfig.AuthoritiesMap.Any())
return authorities;
var attributes = ldapEntry.GetAttributeSet();
if (!string.IsNullOrWhiteSpace(_ldapConfig.GroupsProperty) ||
!attributes.TryGetValue(_ldapConfig.GroupsProperty!, out var groupsAttr) ||
groupsAttr?.StringValueArray == null)
{
return authorities;
}
var groups = groupsAttr.StringValueArray.ToList();
foreach (var authorityMap in _ldapConfig.AuthoritiesMap)
{
if (groups.Exists(g =>
string.Equals(g, authorityMap.Group, StringComparison.CurrentCultureIgnoreCase)))
{
if (!Enum.TryParse<PermissionEnum.RolesType>(authorityMap.Rol, out _))
continue;
authorities.Add(new Authorization
{
UserId = user.Id,
DisplayId = authorityMap.DisplayId,
Rol = authorityMap.Rol
});
}
}
return authorities;
}
catch (Exception e)
{
_logger.LogError("Error getting Authorities Map. Return new empty list. Exception: {e}", e);
return [];
}
}
}