using System; using System.Collections.Generic; using System.Linq; using Opc.Ua; using Serilog; namespace ZB.MOM.WW.OtOpcUa.Host.OpcUa { /// /// Maps configured security profile names to OPC UA instances. /// public static class SecurityProfileResolver { private static readonly ILogger Log = Serilog.Log.ForContext(typeof(SecurityProfileResolver)); private static readonly Dictionary KnownProfiles = new(StringComparer.OrdinalIgnoreCase) { ["None"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.None, SecurityPolicyUri = SecurityPolicies.None }, ["Basic256Sha256-Sign"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.Sign, SecurityPolicyUri = SecurityPolicies.Basic256Sha256 }, ["Basic256Sha256-SignAndEncrypt"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.SignAndEncrypt, SecurityPolicyUri = SecurityPolicies.Basic256Sha256 }, ["Aes128_Sha256_RsaOaep-Sign"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.Sign, SecurityPolicyUri = SecurityPolicies.Aes128_Sha256_RsaOaep }, ["Aes128_Sha256_RsaOaep-SignAndEncrypt"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.SignAndEncrypt, SecurityPolicyUri = SecurityPolicies.Aes128_Sha256_RsaOaep }, ["Aes256_Sha256_RsaPss-Sign"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.Sign, SecurityPolicyUri = SecurityPolicies.Aes256_Sha256_RsaPss }, ["Aes256_Sha256_RsaPss-SignAndEncrypt"] = new ServerSecurityPolicy { SecurityMode = MessageSecurityMode.SignAndEncrypt, SecurityPolicyUri = SecurityPolicies.Aes256_Sha256_RsaPss } }; /// /// Gets the list of valid profile names for validation and documentation. /// public static IReadOnlyCollection ValidProfileNames => KnownProfiles.Keys.ToList().AsReadOnly(); /// /// Resolves the configured profile names to entries. /// Unknown names are skipped with a warning. An empty or fully-invalid list falls back to None. /// /// The profile names from configuration. /// A deduplicated list of server security policies. public static List Resolve(IReadOnlyCollection profileNames) { var resolved = new List(); var seen = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var name in profileNames ?? Array.Empty()) { if (string.IsNullOrWhiteSpace(name)) continue; var trimmed = name.Trim(); if (!seen.Add(trimmed)) { Log.Debug("Skipping duplicate security profile: {Profile}", trimmed); continue; } if (KnownProfiles.TryGetValue(trimmed, out var policy)) resolved.Add(policy); else Log.Warning("Unknown security profile '{Profile}' — skipping. Valid profiles: {ValidProfiles}", trimmed, string.Join(", ", KnownProfiles.Keys)); } if (resolved.Count == 0) { Log.Warning("No valid security profiles configured — falling back to None"); resolved.Add(KnownProfiles["None"]); } return resolved; } } }