108 lines
4.9 KiB
C#
108 lines
4.9 KiB
C#
using Opc.Ua;
|
|
using Opc.Ua.Client;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Net;
|
|
|
|
namespace OpcPks.Core.Services
|
|
{
|
|
public class OpcSessionManager
|
|
{
|
|
private ISession? _session;
|
|
public ISession? Session => _session;
|
|
|
|
public async Task<ISession> GetSessionAsync()
|
|
{
|
|
if (_session != null && _session.Connected) return _session;
|
|
|
|
string serverHostName = "192.168.0.20";
|
|
string endpointUrl = $"opc.tcp://{serverHostName}:4840";
|
|
string applicationUri = "urn:dbsvr:OpcTestClient";
|
|
string userName = "mngr";
|
|
string password = "mngr";
|
|
string pfxPassword = ""; // openssl에서 확인한 비밀번호가 있다면 입력
|
|
|
|
string baseDataPath = "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data/pki";
|
|
string pfxFilePath = Path.Combine(baseDataPath, "own/private/OpcTestClient.pfx");
|
|
|
|
var config = new ApplicationConfiguration {
|
|
ApplicationName = "OpcTestClient",
|
|
ApplicationType = ApplicationType.Client,
|
|
ApplicationUri = applicationUri,
|
|
SecurityConfiguration = new SecurityConfiguration {
|
|
ApplicationCertificate = new CertificateIdentifier {
|
|
StoreType = "Directory",
|
|
StorePath = Path.Combine(baseDataPath, "own"),
|
|
SubjectName = "OpcTestClient"
|
|
},
|
|
TrustedPeerCertificates = new CertificateTrustList {
|
|
StoreType = "Directory",
|
|
StorePath = Path.Combine(baseDataPath, "trusted")
|
|
},
|
|
AutoAcceptUntrustedCertificates = true,
|
|
AddAppCertToTrustedStore = true
|
|
},
|
|
TransportQuotas = new TransportQuotas { OperationTimeout = 60000 },
|
|
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 }
|
|
};
|
|
|
|
// 1. [인증서 강제 로드] Validate 호출 전에 인증서를 명시적으로 로드합니다.
|
|
if (!File.Exists(pfxFilePath)) {
|
|
throw new Exception($"❌ PFX 파일을 찾을 수 없습니다: {pfxFilePath}");
|
|
}
|
|
|
|
try {
|
|
// 리눅스 .NET 호환용 플래그
|
|
var cert = new X509Certificate2(
|
|
pfxFilePath,
|
|
pfxPassword,
|
|
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet
|
|
);
|
|
|
|
// config에 인증서 직접 주입
|
|
config.SecurityConfiguration.ApplicationCertificate.Certificate = cert;
|
|
Console.WriteLine($"✅ [인증서 로드] {cert.Subject}");
|
|
} catch (Exception ex) {
|
|
Console.WriteLine($"❌ [인증서 에러] PFX 로드 실패: {ex.Message}");
|
|
throw;
|
|
}
|
|
|
|
// 2. 설정 검증 (인증서 주입 후 실행)
|
|
await config.Validate(ApplicationType.Client);
|
|
|
|
// Validate 이후 인증서가 풀렸을 경우를 대비해 다시 확인
|
|
if (config.SecurityConfiguration.ApplicationCertificate.Certificate == null) {
|
|
Console.WriteLine("⚠️ [경고] Validate 과정에서 인증서 설정이 유실되어 재할당합니다.");
|
|
config.SecurityConfiguration.ApplicationCertificate.Certificate = new X509Certificate2(pfxFilePath, pfxPassword, X509KeyStorageFlags.MachineKeySet);
|
|
}
|
|
|
|
config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = true; };
|
|
|
|
// 3. 엔드포인트 선택 및 보안 정책 로그
|
|
var endpointDescription = CoreClientUtils.SelectEndpoint(endpointUrl, true);
|
|
var endpointConfiguration = EndpointConfiguration.Create(config);
|
|
var configuredEndpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
|
|
|
|
Console.WriteLine($"📡 [세션] 연결 시도: {endpointUrl}");
|
|
Console.WriteLine($"🔐 [보안] {endpointDescription.SecurityPolicyUri} ({endpointDescription.SecurityMode})");
|
|
|
|
// 4. 세션 생성 시도
|
|
try {
|
|
_session = await Opc.Ua.Client.Session.Create(
|
|
config,
|
|
configuredEndpoint,
|
|
true,
|
|
"OpcPksSession",
|
|
60000,
|
|
new UserIdentity(userName, password),
|
|
null
|
|
);
|
|
Console.WriteLine("🚀 [성공] 하니웰 서버와 연결되었습니다!");
|
|
} catch (ServiceResultException srex) {
|
|
Console.WriteLine($"❌ [OPC 에러] {srex.StatusCode}: {srex.Message}");
|
|
throw;
|
|
}
|
|
|
|
return _session;
|
|
}
|
|
}
|
|
} |