From 6d5bc278d717e7f99d3f9bd136c8d42bf7367dfe Mon Sep 17 00:00:00 2001 From: GiuseppeS Date: Tue, 23 Sep 2025 12:52:49 +0200 Subject: [PATCH] Integrazione base del DB esistente e login tramite LDAP --- .../Components/Account/Pages/Login.razor | 10 +- .../Controllers/LdapController.cs | 101 ++++ .../Data/ApplicationUser.cs | 9 +- .../Data/IntegryControlPanelDbContext.cs | 515 ++++++++++++++++++ ...23102919_AddLdapUserProperties.Designer.cs | 303 +++++++++++ .../20250923102919_AddLdapUserProperties.cs | 100 ++++ .../ApplicationDbContextModelSnapshot.cs | 28 +- .../IntegryControlPanel.csproj | 5 + .../IntegryControlPanel/ApplicationInfo.cs | 31 ++ .../Models/IntegryControlPanel/Client.cs | 19 + .../IntegryControlPanel/Configurazioni.cs | 27 + .../Models/IntegryControlPanel/Customer.cs | 27 + .../IntegryControlPanel/DatabaseEngine.cs | 23 + .../IntegryControlPanel/DatabasesInfo.cs | 21 + .../Models/IntegryControlPanel/Device.cs | 24 + .../IntegryControlPanel/Installation.cs | 32 ++ .../Models/IntegryControlPanel/PvmsInfo.cs | 35 ++ .../Models/IntegryControlPanel/Release.cs | 21 + .../IntegryControlPanel/SalvataggiSoap.cs | 15 + .../Models/IntegryControlPanel/Server.cs | 44 ++ .../Models/IntegryControlPanel/Service.cs | 21 + .../IntegryControlPanel/VwServerLastUpdate.cs | 37 ++ .../IntegryControlPanel/Models/LdapUser.cs | 15 + .../IntegryControlPanel/Program.cs | 14 +- .../Services/ILdapService.cs | 11 + .../Services/LdapService.cs | 193 +++++++ .../Services/LdapSignInManager.cs | 81 +++ .../Services/LdapUserManager.cs | 228 ++++++++ .../appsettings.Development.json | 11 +- .../IntegryControlPanel/appsettings.json | 14 +- 30 files changed, 2002 insertions(+), 13 deletions(-) create mode 100644 IntegryControlPanel/IntegryControlPanel/Controllers/LdapController.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Data/IntegryControlPanelDbContext.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.Designer.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/ApplicationInfo.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Client.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Configurazioni.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Customer.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabaseEngine.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabasesInfo.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Device.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Installation.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/PvmsInfo.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Release.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/SalvataggiSoap.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Server.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Service.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/VwServerLastUpdate.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Models/LdapUser.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Services/ILdapService.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Services/LdapService.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Services/LdapSignInManager.cs create mode 100644 IntegryControlPanel/IntegryControlPanel/Services/LdapUserManager.cs diff --git a/IntegryControlPanel/IntegryControlPanel/Components/Account/Pages/Login.razor b/IntegryControlPanel/IntegryControlPanel/Components/Account/Pages/Login.razor index f8fd7a3..30def34 100644 --- a/IntegryControlPanel/IntegryControlPanel/Components/Account/Pages/Login.razor +++ b/IntegryControlPanel/IntegryControlPanel/Components/Account/Pages/Login.razor @@ -24,8 +24,8 @@ - @@ -82,7 +82,7 @@ { // This doesn't count login failures towards account lockout // To enable password failures to trigger account lockout, set lockoutOnFailure: true - var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); + var result = await SignInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: false); if (result.Succeeded) { Logger.LogInformation("User logged in."); @@ -108,8 +108,8 @@ private sealed class InputModel { [Required] - [EmailAddress] - public string Email { get; set; } = ""; + // [EmailAddress] + public string Username { get; set; } = ""; [Required] [DataType(DataType.Password)] diff --git a/IntegryControlPanel/IntegryControlPanel/Controllers/LdapController.cs b/IntegryControlPanel/IntegryControlPanel/Controllers/LdapController.cs new file mode 100644 index 0000000..6c75d74 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Controllers/LdapController.cs @@ -0,0 +1,101 @@ +using IntegryControlPanel.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace IntegryControlPanel.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class LdapController : ControllerBase + { + private readonly ILdapService _ldapService; + private readonly LdapUserManager _ldapUserManager; + private readonly ILogger _logger; + + public LdapController( + ILdapService ldapService, + LdapUserManager ldapUserManager, + ILogger logger) + { + _ldapService = ldapService; + _ldapUserManager = ldapUserManager; + _logger = logger; + } + + [HttpPost("sync-user")] + [Authorize] + public async Task SyncUser([FromBody] string username) + { + if (string.IsNullOrWhiteSpace(username)) + return BadRequest("Username is required"); + + try + { + var user = await _ldapUserManager.SyncUserFromLdapAsync(username); + if (user == null) + return NotFound($"User {username} not found in LDAP"); + + return Ok(new + { + Message = "User synced successfully", + User = new + { + user.UserName, + user.Email, + user.FirstName, + user.LastName, + user.Department, + user.Title, + user.LastLdapSync + } + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error syncing user {Username}", username); + return StatusCode(500, "Internal server error"); + } + } + + [HttpGet("users-in-group/{groupName}")] + [Authorize] + public async Task GetUsersInGroup(string groupName) + { + if (string.IsNullOrWhiteSpace(groupName)) + return BadRequest("Group name is required"); + + try + { + var users = await _ldapService.GetUsersInGroupAsync(groupName); + return Ok(users); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error getting users in group {GroupName}", groupName); + return StatusCode(500, "Internal server error"); + } + } + + [HttpGet("user/{username}")] + [Authorize] + public async Task GetUser(string username) + { + if (string.IsNullOrWhiteSpace(username)) + return BadRequest("Username is required"); + + try + { + var user = await _ldapService.GetUserAsync(username); + if (user == null) + return NotFound($"User {username} not found in LDAP"); + + return Ok(user); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error getting user {Username}", username); + return StatusCode(500, "Internal server error"); + } + } + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/Data/ApplicationUser.cs b/IntegryControlPanel/IntegryControlPanel/Data/ApplicationUser.cs index 2dc73ae..66863af 100644 --- a/IntegryControlPanel/IntegryControlPanel/Data/ApplicationUser.cs +++ b/IntegryControlPanel/IntegryControlPanel/Data/ApplicationUser.cs @@ -5,6 +5,13 @@ namespace IntegryControlPanel.Data // Add profile data for application users by adding properties to the ApplicationUser class public class ApplicationUser : IdentityUser { + public string? FirstName { get; set; } + public string? LastName { get; set; } + public string? DisplayName { get; set; } + public string? Department { get; set; } + public string? Title { get; set; } + public bool IsLdapUser { get; set; } = false; + public string? LdapUsername { get; set; } + public DateTime? LastLdapSync { get; set; } } - } diff --git a/IntegryControlPanel/IntegryControlPanel/Data/IntegryControlPanelDbContext.cs b/IntegryControlPanel/IntegryControlPanel/Data/IntegryControlPanelDbContext.cs new file mode 100644 index 0000000..922d944 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Data/IntegryControlPanelDbContext.cs @@ -0,0 +1,515 @@ +using System; +using System.Collections.Generic; +using IntegryControlPanel.Models.IntegryControlPanel; +using Microsoft.EntityFrameworkCore; + +namespace IntegryControlPanel.Data; + +public partial class IntegryControlPanelDbContext : DbContext +{ + public IntegryControlPanelDbContext() + { + } + + public IntegryControlPanelDbContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet ApplicationInfos { get; set; } + + public virtual DbSet Clients { get; set; } + + public virtual DbSet Configurazionis { get; set; } + + public virtual DbSet Customers { get; set; } + + public virtual DbSet DatabaseEngines { get; set; } + + public virtual DbSet DatabasesInfos { get; set; } + + public virtual DbSet Devices { get; set; } + + public virtual DbSet Installations { get; set; } + + public virtual DbSet PvmsInfos { get; set; } + + public virtual DbSet Releases { get; set; } + + public virtual DbSet SalvataggiSoaps { get; set; } + + public virtual DbSet Servers { get; set; } + + public virtual DbSet Services { get; set; } + + public virtual DbSet VwServerLastUpdates { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. + => optionsBuilder.UseSqlServer("Server=SERVERDB2019;Database=integry_control_panel_test;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True;"); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__applicat__3213E83F4185DE9F"); + + entity.ToTable("application_infos"); + + entity.HasIndex(e => e.CustomerId, "IDX_D5E65179395C3F3"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.AnnoContab).HasColumnName("anno_contab"); + entity.Property(e => e.AnnoMagaz).HasColumnName("anno_magaz"); + entity.Property(e => e.AnsiPadding) + .IsRequired() + .HasDefaultValueSql("('0')") + .HasColumnName("ansi_padding"); + entity.Property(e => e.ConcatNullYieldsNull) + .IsRequired() + .HasDefaultValueSql("('0')") + .HasColumnName("concat_null_yields_null"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.DelimitedIdentifier) + .IsRequired() + .HasDefaultValueSql("('0')") + .HasColumnName("delimited_identifier"); + entity.Property(e => e.MenuPersonalizzato) + .HasMaxLength(255) + .HasColumnName("menu_personalizzato"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasColumnName("name"); + entity.Property(e => e.NewUpdProgMaga).HasColumnName("new_upd_prog_maga"); + + entity.HasOne(d => d.Customer).WithMany(p => p.ApplicationInfos) + .HasForeignKey(d => d.CustomerId) + .HasConstraintName("FK_D5E65179395C3F3"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__clients__3213E83FFF8DC3E2"); + + entity.ToTable("clients"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.DeviceId) + .HasMaxLength(255) + .HasColumnName("device_id"); + entity.Property(e => e.InsertDate) + .HasPrecision(6) + .HasColumnName("insert_date"); + entity.Property(e => e.LastUpdate) + .HasPrecision(6) + .HasColumnName("last_update"); + entity.Property(e => e.NomeAzienda) + .HasMaxLength(255) + .HasColumnName("nome_azienda"); + entity.Property(e => e.RemoteAddr) + .HasMaxLength(255) + .HasColumnName("remote_addr"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__configur__3213E83FB9077FED"); + + entity.ToTable("configurazioni"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.JavaVersion) + .HasMaxLength(255) + .HasColumnName("java_version"); + entity.Property(e => e.LastUpdate) + .HasPrecision(6) + .HasColumnName("last_update"); + entity.Property(e => e.MaxPermSize) + .HasMaxLength(255) + .HasColumnName("max_perm_size"); + entity.Property(e => e.NomeAzienda) + .HasMaxLength(255) + .HasColumnName("nome_azienda"); + entity.Property(e => e.OsArch) + .HasMaxLength(255) + .HasColumnName("os_arch"); + entity.Property(e => e.OsName) + .HasMaxLength(255) + .HasColumnName("os_name"); + entity.Property(e => e.RemoteAddr) + .HasMaxLength(255) + .HasColumnName("remote_addr"); + entity.Property(e => e.Xms) + .HasMaxLength(255) + .HasColumnName("xms"); + entity.Property(e => e.Xmx) + .HasMaxLength(255) + .HasColumnName("xmx"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__customer__3213E83FD00417AC"); + + entity.ToTable("customers"); + + entity.HasIndex(e => e.Slug, "UNIQ_62534E21989D9B62") + .IsUnique() + .HasFilter("([slug] IS NOT NULL)"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Active) + .IsRequired() + .HasDefaultValueSql("('0')") + .HasColumnName("active"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasColumnName("name"); + entity.Property(e => e.PartitaIva) + .HasMaxLength(255) + .HasColumnName("partita_iva"); + entity.Property(e => e.Slug) + .HasMaxLength(191) + .HasColumnName("slug"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__database__3213E83F8526E221"); + + entity.ToTable("database_engines"); + + entity.HasIndex(e => e.CustomerId, "UNIQ_1D94CC5C9395C3F3") + .IsUnique() + .HasFilter("([customer_id] IS NOT NULL)"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.ProductEdition) + .HasMaxLength(255) + .HasColumnName("product_edition"); + entity.Property(e => e.ProductLevel) + .HasMaxLength(255) + .HasColumnName("product_level"); + entity.Property(e => e.ProductVersion) + .HasMaxLength(255) + .HasColumnName("product_version"); + entity.Property(e => e.ProductVersionName) + .HasMaxLength(255) + .HasColumnName("product_version_name"); + + entity.HasOne(d => d.Customer).WithOne(p => p.DatabaseEngine) + .HasForeignKey(d => d.CustomerId) + .HasConstraintName("FK_1D94CC5C9395C3F3"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__database__3213E83FC619B4B0"); + + entity.ToTable("databases_info"); + + entity.HasIndex(e => e.DatabaseEngineId, "IDX_99DAF4F8AB25983"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.DatabaseEngineId).HasColumnName("database_engine_id"); + entity.Property(e => e.LogicalName) + .HasMaxLength(255) + .HasColumnName("logical_name"); + entity.Property(e => e.MaxSizeMb).HasColumnName("max_size_mb"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasColumnName("name"); + entity.Property(e => e.SizeMb).HasColumnName("size_mb"); + + entity.HasOne(d => d.DatabaseEngine).WithMany(p => p.DatabasesInfos) + .HasForeignKey(d => d.DatabaseEngineId) + .HasConstraintName("FK_99DAF4F8AB25983"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__devices__3213E83F185C7B65"); + + entity.ToTable("devices"); + + entity.HasIndex(e => e.CustomerId, "IDX_11074E9A9395C3F3"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.Info) + .IsUnicode(false) + .HasComment("(DC2Type:simple_array)") + .HasColumnName("info"); + entity.Property(e => e.Ip) + .HasMaxLength(255) + .HasColumnName("ip"); + entity.Property(e => e.Port).HasColumnName("port"); + + entity.HasOne(d => d.Customer).WithMany(p => p.Devices) + .HasForeignKey(d => d.CustomerId) + .HasConstraintName("FK_11074E9A9395C3F3"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__installa__3213E83F11ECD973"); + + entity.ToTable("installations"); + + entity.HasIndex(e => e.ServerId, "IDX_A774F67B1844E6B7"); + + entity.HasIndex(e => e.DeviceId, "IDX_A774F67B94A4C7D4"); + + entity.HasIndex(e => e.ReleaseId, "IDX_A774F67BB12A727D"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.DeviceId).HasColumnName("device_id"); + entity.Property(e => e.InstallDate) + .HasPrecision(6) + .HasColumnName("install_date"); + entity.Property(e => e.LastUpdate) + .HasPrecision(6) + .HasColumnName("last_update"); + entity.Property(e => e.Notes) + .HasMaxLength(255) + .HasColumnName("notes"); + entity.Property(e => e.Options) + .IsUnicode(false) + .HasComment("(DC2Type:simple_array)") + .HasColumnName("options"); + entity.Property(e => e.ReleaseId).HasColumnName("release_id"); + entity.Property(e => e.ServerId).HasColumnName("server_id"); + + entity.HasOne(d => d.Device).WithMany(p => p.Installations) + .HasForeignKey(d => d.DeviceId) + .HasConstraintName("FK_A774F67B94A4C7D4"); + + entity.HasOne(d => d.Release).WithMany(p => p.Installations) + .HasForeignKey(d => d.ReleaseId) + .HasConstraintName("FK_A774F67BB12A727D"); + + entity.HasOne(d => d.Server).WithMany(p => p.Installations) + .HasForeignKey(d => d.ServerId) + .HasConstraintName("FK_A774F67B1844E6B7"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__pvms_inf__3213E83F8EA1FE36"); + + entity.ToTable("pvms_info"); + + entity.HasIndex(e => e.CustomerId, "IDX_4BCCAB779395C3F3"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.DefaultCharset) + .HasMaxLength(255) + .HasColumnName("default_charset"); + entity.Property(e => e.Imagick) + .HasMaxLength(255) + .HasColumnName("imagick"); + entity.Property(e => e.MagicQuotesGpc).HasColumnName("magic_quotes_gpc"); + entity.Property(e => e.MaxExecutionTime).HasColumnName("max_execution_time"); + entity.Property(e => e.MaxInputVars).HasColumnName("max_input_vars"); + entity.Property(e => e.MemoryLimit) + .HasMaxLength(255) + .HasColumnName("memory_limit"); + entity.Property(e => e.PhpVersion) + .HasMaxLength(255) + .HasColumnName("php_version"); + entity.Property(e => e.PostMaxSize) + .HasMaxLength(255) + .HasColumnName("post_max_size"); + entity.Property(e => e.SodiumMissing).HasColumnName("sodium_missing"); + entity.Property(e => e.Timezone) + .HasMaxLength(255) + .HasColumnName("timezone"); + entity.Property(e => e.UploadMaxSize) + .HasMaxLength(255) + .HasColumnName("upload_max_size"); + + entity.HasOne(d => d.Customer).WithMany(p => p.PvmsInfos) + .HasForeignKey(d => d.CustomerId) + .HasConstraintName("FK_4BCCAB779395C3F3"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__releases__3213E83F59E90B83"); + + entity.ToTable("releases"); + + entity.HasIndex(e => e.ServiceId, "IDX_7896E4D1ED5CA9E6"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Changelog) + .IsUnicode(false) + .HasColumnName("changelog"); + entity.Property(e => e.ReleaseDate) + .HasPrecision(6) + .HasColumnName("release_date"); + entity.Property(e => e.ServiceId).HasColumnName("service_id"); + entity.Property(e => e.Version) + .HasMaxLength(255) + .HasColumnName("version"); + + entity.HasOne(d => d.Service).WithMany(p => p.Releases) + .HasForeignKey(d => d.ServiceId) + .HasConstraintName("FK_7896E4D1ED5CA9E6"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__salvatag__3213E83F51C2D8BF"); + + entity.ToTable("salvataggi_soap"); + + entity.HasIndex(e => e.ApplicationInfoId, "IDX_BC9B16D5B635C4CB"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.ApplicationInfoId).HasColumnName("application_info_id"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasColumnName("name"); + + entity.HasOne(d => d.ApplicationInfo).WithMany(p => p.SalvataggiSoaps) + .HasForeignKey(d => d.ApplicationInfoId) + .HasConstraintName("FK_BC9B16D5B635C4CB"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__servers__3213E83F0E4B2C74"); + + entity.ToTable("servers"); + + entity.HasIndex(e => e.CustomerId, "IDX_4F8AF5F79395C3F3"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.CreatedAt) + .HasPrecision(6) + .HasColumnName("created_at"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.Info) + .IsUnicode(false) + .HasComment("(DC2Type:simple_array)") + .HasColumnName("info"); + entity.Property(e => e.Ip) + .HasMaxLength(255) + .HasColumnName("ip"); + entity.Property(e => e.JavaVersion) + .HasMaxLength(255) + .HasColumnName("java_version"); + entity.Property(e => e.LastUpdate) + .HasPrecision(6) + .HasColumnName("last_update"); + entity.Property(e => e.MaxPermSize) + .HasMaxLength(255) + .HasColumnName("max_perm_size"); + entity.Property(e => e.OsArch) + .HasMaxLength(255) + .HasColumnName("os_arch"); + entity.Property(e => e.OsName) + .HasMaxLength(255) + .HasColumnName("os_name"); + entity.Property(e => e.Port).HasColumnName("port"); + entity.Property(e => e.RemoteAddr) + .HasMaxLength(255) + .HasColumnName("remote_addr"); + entity.Property(e => e.UpdatedAt) + .HasPrecision(6) + .HasColumnName("updated_at"); + entity.Property(e => e.Xms) + .HasMaxLength(255) + .HasColumnName("xms"); + entity.Property(e => e.Xmx) + .HasMaxLength(255) + .HasColumnName("xmx"); + + entity.HasOne(d => d.Customer).WithMany(p => p.Servers) + .HasForeignKey(d => d.CustomerId) + .HasConstraintName("FK_4F8AF5F79395C3F3"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id).HasName("PK__services__3213E83FB43C1FE2"); + + entity.ToTable("services"); + + entity.HasIndex(e => e.Slug, "UNIQ_7332E169989D9B62") + .IsUnique() + .HasFilter("([slug] IS NOT NULL)"); + + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Description) + .IsUnicode(false) + .HasColumnName("description"); + entity.Property(e => e.InsertDate) + .HasPrecision(6) + .HasColumnName("insert_date"); + entity.Property(e => e.Language) + .HasMaxLength(255) + .HasColumnName("language"); + entity.Property(e => e.Name) + .HasMaxLength(255) + .HasColumnName("name"); + entity.Property(e => e.Slug) + .HasMaxLength(191) + .HasColumnName("slug"); + }); + + modelBuilder.Entity(entity => + { + entity + .HasNoKey() + .ToView("vw_server_last_update"); + + entity.Property(e => e.CreatedAt) + .HasPrecision(6) + .HasColumnName("created_at"); + entity.Property(e => e.CustomerId).HasColumnName("customer_id"); + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.Info) + .IsUnicode(false) + .HasColumnName("info"); + entity.Property(e => e.Ip) + .HasMaxLength(255) + .HasColumnName("ip"); + entity.Property(e => e.JavaVersion) + .HasMaxLength(255) + .HasColumnName("java_version"); + entity.Property(e => e.LastUpdate) + .HasPrecision(6) + .HasColumnName("last_update"); + entity.Property(e => e.MaxPermSize) + .HasMaxLength(255) + .HasColumnName("max_perm_size"); + entity.Property(e => e.OsArch) + .HasMaxLength(255) + .HasColumnName("os_arch"); + entity.Property(e => e.OsName) + .HasMaxLength(255) + .HasColumnName("os_name"); + entity.Property(e => e.Port).HasColumnName("port"); + entity.Property(e => e.RemoteAddr) + .HasMaxLength(255) + .HasColumnName("remote_addr"); + entity.Property(e => e.UpdatedAt) + .HasPrecision(6) + .HasColumnName("updated_at"); + entity.Property(e => e.Xms) + .HasMaxLength(255) + .HasColumnName("xms"); + entity.Property(e => e.Xmx) + .HasMaxLength(255) + .HasColumnName("xmx"); + }); + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.Designer.cs b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.Designer.cs new file mode 100644 index 0000000..dbad3b0 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.Designer.cs @@ -0,0 +1,303 @@ +// +using System; +using IntegryControlPanel.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace IntegryControlPanel.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250923102919_AddLdapUserProperties")] + partial class AddLdapUserProperties + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("IntegryControlPanel.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Department") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("IsLdapUser") + .HasColumnType("bit"); + + b.Property("LastLdapSync") + .HasColumnType("datetime2"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.Property("LdapUsername") + .HasColumnType("nvarchar(max)"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("IntegryControlPanel.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("IntegryControlPanel.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("IntegryControlPanel.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("IntegryControlPanel.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.cs b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.cs new file mode 100644 index 0000000..2d878dc --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/20250923102919_AddLdapUserProperties.cs @@ -0,0 +1,100 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace IntegryControlPanel.Migrations +{ + /// + public partial class AddLdapUserProperties : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Department", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "DisplayName", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "FirstName", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "IsLdapUser", + table: "AspNetUsers", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "LastLdapSync", + table: "AspNetUsers", + type: "datetime2", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastName", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "LdapUsername", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Title", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Department", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "DisplayName", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "FirstName", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "IsLdapUser", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "LastLdapSync", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "LastName", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "LdapUsername", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "Title", + table: "AspNetUsers"); + } + } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/ApplicationDbContextModelSnapshot.cs index db85d01..58e27db 100644 --- a/IntegryControlPanel/IntegryControlPanel/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/IntegryControlPanel/IntegryControlPanel/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1,4 +1,4 @@ -// +// using System; using IntegryControlPanel.Data; using Microsoft.EntityFrameworkCore; @@ -17,7 +17,7 @@ namespace IntegryControlPanel.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("ProductVersion", "9.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -34,6 +34,12 @@ namespace IntegryControlPanel.Migrations .IsConcurrencyToken() .HasColumnType("nvarchar(max)"); + b.Property("Department") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + b.Property("Email") .HasMaxLength(256) .HasColumnType("nvarchar(256)"); @@ -41,6 +47,21 @@ namespace IntegryControlPanel.Migrations b.Property("EmailConfirmed") .HasColumnType("bit"); + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("IsLdapUser") + .HasColumnType("bit"); + + b.Property("LastLdapSync") + .HasColumnType("datetime2"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.Property("LdapUsername") + .HasColumnType("nvarchar(max)"); + b.Property("LockoutEnabled") .HasColumnType("bit"); @@ -67,6 +88,9 @@ namespace IntegryControlPanel.Migrations b.Property("SecurityStamp") .HasColumnType("nvarchar(max)"); + b.Property("Title") + .HasColumnType("nvarchar(max)"); + b.Property("TwoFactorEnabled") .HasColumnType("bit"); diff --git a/IntegryControlPanel/IntegryControlPanel/IntegryControlPanel.csproj b/IntegryControlPanel/IntegryControlPanel/IntegryControlPanel.csproj index c4cbe2e..a872a33 100644 --- a/IntegryControlPanel/IntegryControlPanel/IntegryControlPanel.csproj +++ b/IntegryControlPanel/IntegryControlPanel/IntegryControlPanel.csproj @@ -9,6 +9,11 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/ApplicationInfo.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/ApplicationInfo.cs new file mode 100644 index 0000000..72df63f --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/ApplicationInfo.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class ApplicationInfo +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string Name { get; set; } = null!; + + public bool NewUpdProgMaga { get; set; } + + public string? MenuPersonalizzato { get; set; } + + public int? AnnoMagaz { get; set; } + + public int? AnnoContab { get; set; } + + public bool? AnsiPadding { get; set; } + + public bool? DelimitedIdentifier { get; set; } + + public bool? ConcatNullYieldsNull { get; set; } + + public virtual Customer? Customer { get; set; } + + public virtual ICollection SalvataggiSoaps { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Client.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Client.cs new file mode 100644 index 0000000..b2910e0 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Client.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Client +{ + public int Id { get; set; } + + public string NomeAzienda { get; set; } = null!; + + public string DeviceId { get; set; } = null!; + + public DateTime? LastUpdate { get; set; } + + public DateTime InsertDate { get; set; } + + public string? RemoteAddr { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Configurazioni.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Configurazioni.cs new file mode 100644 index 0000000..0d8f461 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Configurazioni.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Configurazioni +{ + public int Id { get; set; } + + public string NomeAzienda { get; set; } = null!; + + public string? JavaVersion { get; set; } + + public string? OsArch { get; set; } + + public string? OsName { get; set; } + + public string? Xmx { get; set; } + + public string? Xms { get; set; } + + public string? MaxPermSize { get; set; } + + public DateTime? LastUpdate { get; set; } + + public string? RemoteAddr { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Customer.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Customer.cs new file mode 100644 index 0000000..5a7bded --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Customer.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Customer +{ + public int Id { get; set; } + + public string Name { get; set; } = null!; + + public string Slug { get; set; } = null!; + + public bool? Active { get; set; } + + public string? PartitaIva { get; set; } + + public virtual ICollection ApplicationInfos { get; set; } = new List(); + + public virtual DatabaseEngine? DatabaseEngine { get; set; } + + public virtual ICollection Devices { get; set; } = new List(); + + public virtual ICollection PvmsInfos { get; set; } = new List(); + + public virtual ICollection Servers { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabaseEngine.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabaseEngine.cs new file mode 100644 index 0000000..bad1b2d --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabaseEngine.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class DatabaseEngine +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string ProductVersion { get; set; } = null!; + + public string ProductVersionName { get; set; } = null!; + + public string ProductLevel { get; set; } = null!; + + public string ProductEdition { get; set; } = null!; + + public virtual Customer? Customer { get; set; } + + public virtual ICollection DatabasesInfos { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabasesInfo.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabasesInfo.cs new file mode 100644 index 0000000..16cbb17 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/DatabasesInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class DatabasesInfo +{ + public int Id { get; set; } + + public int? DatabaseEngineId { get; set; } + + public string Name { get; set; } = null!; + + public string LogicalName { get; set; } = null!; + + public int SizeMb { get; set; } + + public int MaxSizeMb { get; set; } + + public virtual DatabaseEngine? DatabaseEngine { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Device.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Device.cs new file mode 100644 index 0000000..907772c --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Device.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Device +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string Ip { get; set; } = null!; + + public int Port { get; set; } + + /// + /// (DC2Type:simple_array) + /// + public string Info { get; set; } = null!; + + public virtual Customer? Customer { get; set; } + + public virtual ICollection Installations { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Installation.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Installation.cs new file mode 100644 index 0000000..737f1c7 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Installation.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Installation +{ + public int Id { get; set; } + + public int? ReleaseId { get; set; } + + public int? ServerId { get; set; } + + public int? DeviceId { get; set; } + + public string? Notes { get; set; } + + /// + /// (DC2Type:simple_array) + /// + public string Options { get; set; } = null!; + + public DateTime InstallDate { get; set; } + + public DateTime LastUpdate { get; set; } + + public virtual Device? Device { get; set; } + + public virtual Release? Release { get; set; } + + public virtual Server? Server { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/PvmsInfo.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/PvmsInfo.cs new file mode 100644 index 0000000..429361e --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/PvmsInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class PvmsInfo +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string PhpVersion { get; set; } = null!; + + public string Timezone { get; set; } = null!; + + public string Imagick { get; set; } = null!; + + public bool SodiumMissing { get; set; } + + public int MaxExecutionTime { get; set; } + + public bool MagicQuotesGpc { get; set; } + + public string DefaultCharset { get; set; } = null!; + + public string MemoryLimit { get; set; } = null!; + + public string PostMaxSize { get; set; } = null!; + + public string UploadMaxSize { get; set; } = null!; + + public int MaxInputVars { get; set; } + + public virtual Customer? Customer { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Release.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Release.cs new file mode 100644 index 0000000..5c5a2c5 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Release.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Release +{ + public int Id { get; set; } + + public int? ServiceId { get; set; } + + public string Version { get; set; } = null!; + + public string? Changelog { get; set; } + + public DateTime ReleaseDate { get; set; } + + public virtual ICollection Installations { get; set; } = new List(); + + public virtual Service? Service { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/SalvataggiSoap.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/SalvataggiSoap.cs new file mode 100644 index 0000000..c15cbb3 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/SalvataggiSoap.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class SalvataggiSoap +{ + public int Id { get; set; } + + public int? ApplicationInfoId { get; set; } + + public string Name { get; set; } = null!; + + public virtual ApplicationInfo? ApplicationInfo { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Server.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Server.cs new file mode 100644 index 0000000..e9326f7 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Server.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Server +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string? Ip { get; set; } + + public int? Port { get; set; } + + /// + /// (DC2Type:simple_array) + /// + public string? Info { get; set; } + + public string? JavaVersion { get; set; } + + public string? OsArch { get; set; } + + public string? OsName { get; set; } + + public string? Xmx { get; set; } + + public string? Xms { get; set; } + + public string? MaxPermSize { get; set; } + + public DateTime? LastUpdate { get; set; } + + public string? RemoteAddr { get; set; } + + public DateTime? CreatedAt { get; set; } + + public DateTime? UpdatedAt { get; set; } + + public virtual Customer? Customer { get; set; } + + public virtual ICollection Installations { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Service.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Service.cs new file mode 100644 index 0000000..f6693d9 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/Service.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class Service +{ + public int Id { get; set; } + + public string Name { get; set; } = null!; + + public string Slug { get; set; } = null!; + + public string? Language { get; set; } + + public string? Description { get; set; } + + public DateTime InsertDate { get; set; } + + public virtual ICollection Releases { get; set; } = new List(); +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/VwServerLastUpdate.cs b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/VwServerLastUpdate.cs new file mode 100644 index 0000000..85fd7af --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/IntegryControlPanel/VwServerLastUpdate.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace IntegryControlPanel.Models.IntegryControlPanel; + +public partial class VwServerLastUpdate +{ + public int Id { get; set; } + + public int? CustomerId { get; set; } + + public string? Ip { get; set; } + + public int? Port { get; set; } + + public string? Info { get; set; } + + public string? JavaVersion { get; set; } + + public string? OsArch { get; set; } + + public string? OsName { get; set; } + + public string? Xmx { get; set; } + + public string? Xms { get; set; } + + public string? MaxPermSize { get; set; } + + public DateTime? LastUpdate { get; set; } + + public string? RemoteAddr { get; set; } + + public DateTime? CreatedAt { get; set; } + + public DateTime? UpdatedAt { get; set; } +} diff --git a/IntegryControlPanel/IntegryControlPanel/Models/LdapUser.cs b/IntegryControlPanel/IntegryControlPanel/Models/LdapUser.cs new file mode 100644 index 0000000..dbcea68 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Models/LdapUser.cs @@ -0,0 +1,15 @@ +namespace IntegryControlPanel.Models +{ + public class LdapUser + { + public string Username { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; + public List Groups { get; set; } = new(); + public string? Department { get; set; } + public string? Title { get; set; } + public string? PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/Program.cs b/IntegryControlPanel/IntegryControlPanel/Program.cs index fd43237..e13f3b2 100644 --- a/IntegryControlPanel/IntegryControlPanel/Program.cs +++ b/IntegryControlPanel/IntegryControlPanel/Program.cs @@ -2,6 +2,7 @@ using IntegryControlPanel.Client.Pages; using IntegryControlPanel.Components; using IntegryControlPanel.Components.Account; using IntegryControlPanel.Data; +using IntegryControlPanel.Services; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using MudBlazor.Services; @@ -16,6 +17,9 @@ builder.Services.AddRazorComponents() .AddInteractiveWebAssemblyComponents() .AddAuthenticationStateSerialization(); +// Add controllers +builder.Services.AddControllers(); + builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -35,9 +39,13 @@ builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddIdentityCore(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores() - .AddSignInManager() + .AddSignInManager() .AddDefaultTokenProviders(); +// Registra i servizi LDAP +builder.Services.AddScoped(); +builder.Services.AddScoped(); + builder.Services.AddSingleton, IdentityNoOpEmailSender>(); var app = builder.Build(); @@ -57,7 +65,6 @@ else app.UseHttpsRedirection(); - app.UseAntiforgery(); app.MapStaticAssets(); @@ -65,6 +72,9 @@ app.MapRazorComponents() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(typeof(IntegryControlPanel.Client._Imports).Assembly); +// Map controllers +app.MapControllers(); + // Add additional endpoints required by the Identity /Account Razor components. app.MapAdditionalIdentityEndpoints(); diff --git a/IntegryControlPanel/IntegryControlPanel/Services/ILdapService.cs b/IntegryControlPanel/IntegryControlPanel/Services/ILdapService.cs new file mode 100644 index 0000000..1e1e0b0 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Services/ILdapService.cs @@ -0,0 +1,11 @@ +using IntegryControlPanel.Models; + +namespace IntegryControlPanel.Services +{ + public interface ILdapService + { + Task AuthenticateAsync(string username, string password); + Task GetUserAsync(string username); + Task> GetUsersInGroupAsync(string groupName); + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/Services/LdapService.cs b/IntegryControlPanel/IntegryControlPanel/Services/LdapService.cs new file mode 100644 index 0000000..df7381f --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Services/LdapService.cs @@ -0,0 +1,193 @@ +using IntegryControlPanel.Models; +using IntegryControlPanel.Services; +using System.DirectoryServices.Protocols; +using System.Net; +using System.Text; + +namespace IntegryControlPanel.Services +{ + public class LdapService : ILdapService + { + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + + private string LdapServer => _configuration["LDAP:Server"] ?? throw new InvalidOperationException("LDAP Server not configured"); + private int LdapPort => int.Parse(_configuration["LDAP:Port"] ?? "389"); + private string BaseDn => _configuration["LDAP:BaseDN"] ?? throw new InvalidOperationException("LDAP BaseDN not configured"); + private string ServiceAccountDn => _configuration["LDAP:ServiceAccountDN"] ?? throw new InvalidOperationException("LDAP ServiceAccountDN not configured"); + private string ServiceAccountPassword => _configuration["LDAP:ServiceAccountPassword"] ?? throw new InvalidOperationException("LDAP ServiceAccountPassword not configured"); + private bool UseSSL => bool.Parse(_configuration["LDAP:UseSSL"] ?? "false"); + + public LdapService(IConfiguration configuration, ILogger logger) + { + _configuration = configuration; + _logger = logger; + } + + public async Task AuthenticateAsync(string username, string password) + { + if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) + return null; + + try + { + using var connection = new LdapConnection(new LdapDirectoryIdentifier(LdapServer, LdapPort)); + + if (UseSSL) + { + connection.SessionOptions.SecureSocketLayer = true; + } + + // Prova prima a fare bind con le credenziali utente per autenticare + string userDn = $"cn={username},{BaseDn}"; + connection.Credential = new NetworkCredential(userDn, password); + connection.AuthType = AuthType.Basic; + + await Task.Run(() => connection.Bind()); + + // Se l'autenticazione ha successo, ottieni le informazioni dell'utente + var user = await GetUserInfoAsync(connection, username); + + return user; + } + catch (LdapException ex) + { + _logger.LogWarning("LDAP authentication failed for user {Username}: {Message}", username, ex.Message); + return null; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error during LDAP authentication for user {Username}", username); + return null; + } + } + + public async Task GetUserAsync(string username) + { + try + { + using var connection = await CreateServiceConnectionAsync(); + return await GetUserInfoAsync(connection, username); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error getting user {Username} from LDAP", username); + return null; + } + } + + public async Task> GetUsersInGroupAsync(string groupName) + { + try + { + using var connection = await CreateServiceConnectionAsync(); + + var searchFilter = $"(&(objectClass=person)(memberOf=cn={groupName},{BaseDn}))"; + var searchRequest = new SearchRequest(BaseDn, searchFilter, SearchScope.Subtree); + searchRequest.Attributes.AddRange(new[] { "cn", "mail", "givenName", "sn", "displayName", "memberOf", "department", "title", "telephoneNumber" }); + + var response = (SearchResponse)await Task.Run(() => connection.SendRequest(searchRequest)); + var users = new List(); + + foreach (SearchResultEntry entry in response.Entries) + { + var user = MapLdapEntryToUser(entry); + if (user != null) + users.Add(user); + } + + return users; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error getting users in group {GroupName} from LDAP", groupName); + return Enumerable.Empty(); + } + } + + private async Task CreateServiceConnectionAsync() + { + var connection = new LdapConnection(new LdapDirectoryIdentifier(LdapServer, LdapPort)); + + if (UseSSL) + { + connection.SessionOptions.SecureSocketLayer = true; + } + + connection.Credential = new NetworkCredential(ServiceAccountDn, ServiceAccountPassword); + connection.AuthType = AuthType.Basic; + + await Task.Run(() => connection.Bind()); + + return connection; + } + + private async Task GetUserInfoAsync(LdapConnection connection, string username) + { + var searchFilter = $"(&(objectClass=person)(cn={username}))"; + var searchRequest = new SearchRequest(BaseDn, searchFilter, SearchScope.Subtree); + searchRequest.Attributes.AddRange(new[] { "cn", "mail", "givenName", "sn", "displayName", "memberOf", "department", "title", "telephoneNumber" }); + + var response = (SearchResponse)await Task.Run(() => connection.SendRequest(searchRequest)); + + if (response.Entries.Count == 0) + return null; + + return MapLdapEntryToUser(response.Entries[0]); + } + + private LdapUser? MapLdapEntryToUser(SearchResultEntry entry) + { + try + { + var user = new LdapUser + { + Username = GetAttributeValue(entry, "cn") ?? string.Empty, + Email = GetAttributeValue(entry, "mail") ?? string.Empty, + FirstName = GetAttributeValue(entry, "givenName") ?? string.Empty, + LastName = GetAttributeValue(entry, "sn") ?? string.Empty, + DisplayName = GetAttributeValue(entry, "displayName") ?? string.Empty, + Department = GetAttributeValue(entry, "department"), + Title = GetAttributeValue(entry, "title"), + PhoneNumber = GetAttributeValue(entry, "telephoneNumber") + }; + + // Estrai i gruppi + if (entry.Attributes.Contains("memberOf")) + { + foreach (var group in entry.Attributes["memberOf"].GetValues(typeof(string)).Cast()) + { + // Estrai solo il nome del gruppo dal DN + var groupName = ExtractGroupNameFromDn(group); + if (!string.IsNullOrEmpty(groupName)) + user.Groups.Add(groupName); + } + } + + return user; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error mapping LDAP entry to user"); + return null; + } + } + + private string? GetAttributeValue(SearchResultEntry entry, string attributeName) + { + if (!entry.Attributes.Contains(attributeName)) + return null; + + var values = entry.Attributes[attributeName].GetValues(typeof(string)); + return values.Length > 0 ? values[0] as string : null; + } + + private string ExtractGroupNameFromDn(string groupDn) + { + // Estrai il nome del gruppo da un DN come "cn=GroupName,ou=Groups,dc=domain,dc=com" + var parts = groupDn.Split(','); + var cnPart = parts.FirstOrDefault(p => p.Trim().StartsWith("cn=", StringComparison.OrdinalIgnoreCase)); + return cnPart?.Substring(3) ?? string.Empty; + } + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/Services/LdapSignInManager.cs b/IntegryControlPanel/IntegryControlPanel/Services/LdapSignInManager.cs new file mode 100644 index 0000000..218a583 --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Services/LdapSignInManager.cs @@ -0,0 +1,81 @@ +using IntegryControlPanel.Data; +using IntegryControlPanel.Services; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; + +namespace IntegryControlPanel.Services +{ + public class LdapSignInManager : SignInManager + { + private readonly LdapUserManager _ldapUserManager; + private readonly ILogger _logger; + + public LdapSignInManager( + UserManager userManager, + IHttpContextAccessor contextAccessor, + IUserClaimsPrincipalFactory claimsFactory, + IOptions optionsAccessor, + ILogger> logger, + IAuthenticationSchemeProvider schemes, + IUserConfirmation confirmation, + LdapUserManager ldapUserManager, + ILogger ldapLogger) + : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation) + { + _ldapUserManager = ldapUserManager; + _logger = ldapLogger; + } + + public override async Task PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure) + { + try + { + // Prima tenta l'autenticazione LDAP + var ldapUser = await _ldapUserManager.AuthenticateAsync(userName, password); + + if (ldapUser != null) + { + _logger.LogInformation("LDAP authentication successful for user {Username}", userName); + + // Accedi all'utente + await SignInAsync(ldapUser, isPersistent); + return SignInResult.Success; + } + + _logger.LogWarning("LDAP authentication failed for user {Username}, trying local authentication", userName); + + // Se l'autenticazione LDAP fallisce, prova con l'autenticazione locale + return await base.PasswordSignInAsync(userName, password, isPersistent, lockoutOnFailure); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error during sign in for user {Username}", userName); + return SignInResult.Failed; + } + } + + public async Task LdapSignInAsync(string userName, string password, bool isPersistent) + { + try + { + var ldapUser = await _ldapUserManager.AuthenticateAsync(userName, password); + + if (ldapUser == null) + { + _logger.LogWarning("LDAP authentication failed for user {Username}", userName); + return SignInResult.Failed; + } + + await SignInAsync(ldapUser, isPersistent); + _logger.LogInformation("LDAP sign in successful for user {Username}", userName); + return SignInResult.Success; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error during LDAP sign in for user {Username}", userName); + return SignInResult.Failed; + } + } + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/Services/LdapUserManager.cs b/IntegryControlPanel/IntegryControlPanel/Services/LdapUserManager.cs new file mode 100644 index 0000000..bb072dc --- /dev/null +++ b/IntegryControlPanel/IntegryControlPanel/Services/LdapUserManager.cs @@ -0,0 +1,228 @@ +using IntegryControlPanel.Data; +using IntegryControlPanel.Services; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +namespace IntegryControlPanel.Services +{ + public class LdapUserManager : IDisposable + { + private readonly UserManager _userManager; + private readonly ILdapService _ldapService; + private readonly ILogger _logger; + + public LdapUserManager( + UserManager userManager, + ILdapService ldapService, + ILogger logger) + { + _userManager = userManager; + _ldapService = ldapService; + _logger = logger; + } + + public async Task AuthenticateAsync(string username, string password) + { + try + { + // Prima tenta l'autenticazione LDAP + var ldapUser = await _ldapService.AuthenticateAsync(username, password); + if (ldapUser == null) + { + _logger.LogWarning("LDAP authentication failed for user {Username}", username); + return null; + } + + // Cerca l'utente esistente nel database locale + var existingUser = await _userManager.Users + .FirstOrDefaultAsync(u => u.LdapUsername == username || u.UserName == username); + + if (existingUser != null) + { + // Aggiorna le informazioni dell'utente esistente + await UpdateUserFromLdapAsync(existingUser, ldapUser); + return existingUser; + } + + // Crea un nuovo utente se non esiste + var newUser = await CreateUserFromLdapAsync(ldapUser); + return newUser; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error during LDAP authentication for user {Username}", username); + return null; + } + } + + public async Task SyncUserFromLdapAsync(string username) + { + try + { + var ldapUser = await _ldapService.GetUserAsync(username); + if (ldapUser == null) + return null; + + var existingUser = await _userManager.Users + .FirstOrDefaultAsync(u => u.LdapUsername == username || u.UserName == username); + + if (existingUser != null) + { + await UpdateUserFromLdapAsync(existingUser, ldapUser); + return existingUser; + } + + return await CreateUserFromLdapAsync(ldapUser); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error syncing user {Username} from LDAP", username); + return null; + } + } + + private async Task CreateUserFromLdapAsync(Models.LdapUser ldapUser) + { + var user = new ApplicationUser + { + UserName = ldapUser.Username, + Email = ldapUser.Email, + EmailConfirmed = true, // Gli utenti LDAP sono considerati verificati + FirstName = ldapUser.FirstName, + LastName = ldapUser.LastName, + DisplayName = ldapUser.DisplayName, + Department = ldapUser.Department, + Title = ldapUser.Title, + PhoneNumber = ldapUser.PhoneNumber, + IsLdapUser = true, + LdapUsername = ldapUser.Username, + LastLdapSync = DateTime.UtcNow + }; + + var result = await _userManager.CreateAsync(user); + if (!result.Succeeded) + { + var errors = string.Join(", ", result.Errors.Select(e => e.Description)); + throw new InvalidOperationException($"Failed to create user: {errors}"); + } + + // Aggiungi ruoli basati sui gruppi LDAP se necessario + await AssignRolesFromLdapGroupsAsync(user, ldapUser.Groups); + + _logger.LogInformation("Created new user {Username} from LDAP", ldapUser.Username); + return user; + } + + private async Task UpdateUserFromLdapAsync(ApplicationUser user, Models.LdapUser ldapUser) + { + bool hasChanges = false; + + if (user.Email != ldapUser.Email) + { + user.Email = ldapUser.Email; + hasChanges = true; + } + + if (user.FirstName != ldapUser.FirstName) + { + user.FirstName = ldapUser.FirstName; + hasChanges = true; + } + + if (user.LastName != ldapUser.LastName) + { + user.LastName = ldapUser.LastName; + hasChanges = true; + } + + if (user.DisplayName != ldapUser.DisplayName) + { + user.DisplayName = ldapUser.DisplayName; + hasChanges = true; + } + + if (user.Department != ldapUser.Department) + { + user.Department = ldapUser.Department; + hasChanges = true; + } + + if (user.Title != ldapUser.Title) + { + user.Title = ldapUser.Title; + hasChanges = true; + } + + if (user.PhoneNumber != ldapUser.PhoneNumber) + { + user.PhoneNumber = ldapUser.PhoneNumber; + hasChanges = true; + } + + user.LastLdapSync = DateTime.UtcNow; + user.IsLdapUser = true; + user.LdapUsername = ldapUser.Username; + + if (hasChanges) + { + var result = await _userManager.UpdateAsync(user); + if (!result.Succeeded) + { + var errors = string.Join(", ", result.Errors.Select(e => e.Description)); + _logger.LogError("Failed to update user {Username}: {Errors}", user.UserName, errors); + } + else + { + _logger.LogInformation("Updated user {Username} from LDAP", user.UserName); + } + } + + // Aggiorna ruoli basati sui gruppi LDAP + await AssignRolesFromLdapGroupsAsync(user, ldapUser.Groups); + } + + private async Task AssignRolesFromLdapGroupsAsync(ApplicationUser user, List ldapGroups) + { + // Implementa la logica di mappatura tra gruppi LDAP e ruoli dell'applicazione + // Esempio di mappatura: + var roleMapping = new Dictionary + { + { "Administrators", "Admin" }, + { "IT-Support", "ITSupport" }, + { "Users", "User" } + }; + + var currentRoles = await _userManager.GetRolesAsync(user); + var newRoles = new List(); + + foreach (var ldapGroup in ldapGroups) + { + if (roleMapping.ContainsKey(ldapGroup)) + { + newRoles.Add(roleMapping[ldapGroup]); + } + } + + // Rimuovi ruoli che non dovrebbero più essere assegnati + var rolesToRemove = currentRoles.Except(newRoles).ToList(); + if (rolesToRemove.Any()) + { + await _userManager.RemoveFromRolesAsync(user, rolesToRemove); + _logger.LogInformation("Removed roles {Roles} from user {Username}", string.Join(", ", rolesToRemove), user.UserName); + } + + // Aggiungi nuovi ruoli + var rolesToAdd = newRoles.Except(currentRoles).ToList(); + if (rolesToAdd.Any()) + { + await _userManager.AddToRolesAsync(user, rolesToAdd); + _logger.LogInformation("Added roles {Roles} to user {Username}", string.Join(", ", rolesToAdd), user.UserName); + } + } + + public void Dispose() + { + // Non disporre di _userManager poiché è gestito dal DI container + } + } +} \ No newline at end of file diff --git a/IntegryControlPanel/IntegryControlPanel/appsettings.Development.json b/IntegryControlPanel/IntegryControlPanel/appsettings.Development.json index 0c208ae..063138a 100644 --- a/IntegryControlPanel/IntegryControlPanel/appsettings.Development.json +++ b/IntegryControlPanel/IntegryControlPanel/appsettings.Development.json @@ -1,8 +1,17 @@ { + "LDAP": { + "Server": "192.168.2.208", + "Port": "389", + "BaseDN": "OU=Azure AD,DC=studio-ml,DC=local", + "ServiceAccountDN": "CN=Administrator,CN=Users,DC=studio-ml,DC=local", + "ServiceAccountPassword": "inpmiy", + "UseSSL": "false" + }, "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "IntegryControlPanel.Services": "Debug" } } } diff --git a/IntegryControlPanel/IntegryControlPanel/appsettings.json b/IntegryControlPanel/IntegryControlPanel/appsettings.json index e29b175..fbe8a25 100644 --- a/IntegryControlPanel/IntegryControlPanel/appsettings.json +++ b/IntegryControlPanel/IntegryControlPanel/appsettings.json @@ -1,11 +1,21 @@ { "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-IntegryControlPanel-c1120793-85cd-450e-893b-978f0af6aeab;Trusted_Connection=True;MultipleActiveResultSets=true" + "DefaultConnection": "Server=SERVERDB2019;Database=integry_control_panel_test;Trusted_Connection=True;MultipleActiveResultSets=true" + + }, + "LDAP": { + "Server": "your-domain-controller.domain.com", + "Port": "389", + "BaseDN": "DC=domain,DC=com", + "ServiceAccountDN": "CN=ServiceAccount,CN=Users,DC=domain,DC=com", + "ServiceAccountPassword": "your-service-account-password", + "UseSSL": "false" }, "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Warning", + "IntegryControlPanel.Services": "Information" } }, "AllowedHosts": "*"