big changes
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using ZA.CoreService.ESBCertificateManager.Models;
|
||||
|
||||
namespace ZA.CoreService.ESBCertificateManager.Services;
|
||||
|
||||
public sealed class SonicCredentialTester
|
||||
{
|
||||
private readonly RuntimeSettings _runtimeSettings;
|
||||
|
||||
public SonicCredentialTester(
|
||||
RuntimeSettings runtimeSettings)
|
||||
{
|
||||
_runtimeSettings =
|
||||
runtimeSettings
|
||||
?? throw new ArgumentNullException(
|
||||
nameof(runtimeSettings));
|
||||
}
|
||||
|
||||
public async Task<CredentialTestResult> TestAsync(
|
||||
SonicSystemOption system,
|
||||
string userName,
|
||||
string secret,
|
||||
string containerName,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(system);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"Der Sonic-Benutzername fehlt.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(secret))
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"Das Sonic-Kennwort fehlt.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(containerName))
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"Für den Verbindungstest fehlt ein Container.");
|
||||
}
|
||||
|
||||
string javaPath =
|
||||
PathResolver.ResolvePath(
|
||||
_runtimeSettings.JavaExecutablePath);
|
||||
|
||||
string libraryPath =
|
||||
PathResolver.ResolvePath(
|
||||
_runtimeSettings.SonicClientLibraryPath);
|
||||
|
||||
string? toolsPath =
|
||||
ResolveToolsDirectory();
|
||||
|
||||
if (!File.Exists(javaPath))
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
$"Java wurde nicht gefunden: {javaPath}");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(libraryPath))
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
$"Der Sonic-JAR-Ordner wurde nicht gefunden: {libraryPath}");
|
||||
}
|
||||
|
||||
if (toolsPath is null)
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"SonicMfContainerTool.class wurde nicht gefunden.");
|
||||
}
|
||||
|
||||
string[] jars =
|
||||
Directory.GetFiles(
|
||||
libraryPath,
|
||||
"*.jar",
|
||||
SearchOption.TopDirectoryOnly);
|
||||
|
||||
if (jars.Length == 0)
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"Im Sonic-Client-Ordner wurden keine JAR-Dateien gefunden.");
|
||||
}
|
||||
|
||||
string classpath =
|
||||
toolsPath
|
||||
+ Path.PathSeparator
|
||||
+ string.Join(
|
||||
Path.PathSeparator,
|
||||
jars.OrderBy(
|
||||
Path.GetFileName,
|
||||
StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
FileName = javaPath,
|
||||
WorkingDirectory = toolsPath,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8,
|
||||
StandardErrorEncoding = Encoding.UTF8,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
startInfo.ArgumentList.Add("-cp");
|
||||
startInfo.ArgumentList.Add(classpath);
|
||||
startInfo.ArgumentList.Add(
|
||||
"SonicMfContainerTool");
|
||||
|
||||
startInfo.ArgumentList.Add("validate");
|
||||
|
||||
startInfo.ArgumentList.Add("--domain");
|
||||
startInfo.ArgumentList.Add(
|
||||
system.DomainName);
|
||||
|
||||
startInfo.ArgumentList.Add("--url");
|
||||
startInfo.ArgumentList.Add(
|
||||
system.ConnectionUrl);
|
||||
|
||||
startInfo.ArgumentList.Add("--user");
|
||||
startInfo.ArgumentList.Add(
|
||||
userName.Trim());
|
||||
|
||||
startInfo.ArgumentList.Add("--container");
|
||||
startInfo.ArgumentList.Add(
|
||||
containerName);
|
||||
|
||||
startInfo.ArgumentList.Add("--timeout");
|
||||
startInfo.ArgumentList.Add("30");
|
||||
|
||||
startInfo.Environment[
|
||||
"ESB_SONIC_PASSWORD"] = secret;
|
||||
|
||||
using Process process = new()
|
||||
{
|
||||
StartInfo = startInfo
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (!process.Start())
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
"Der Java-Prozess konnte nicht gestartet werden.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return CredentialTestResult.Failed(
|
||||
$"Java konnte nicht gestartet werden: {ex.Message}");
|
||||
}
|
||||
|
||||
Task<string> standardOutputTask =
|
||||
process.StandardOutput.ReadToEndAsync();
|
||||
|
||||
Task<string> standardErrorTask =
|
||||
process.StandardError.ReadToEndAsync();
|
||||
|
||||
using CancellationTokenSource timeoutSource =
|
||||
CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken);
|
||||
|
||||
timeoutSource.CancelAfter(
|
||||
TimeSpan.FromSeconds(35));
|
||||
|
||||
try
|
||||
{
|
||||
await process.WaitForExitAsync(
|
||||
timeoutSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
when (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
TryKill(process);
|
||||
|
||||
return CredentialTestResult.Failed(
|
||||
"Der Sonic-Verbindungstest hat das Zeitlimit überschritten.");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
TryKill(process);
|
||||
throw;
|
||||
}
|
||||
|
||||
string standardOutput =
|
||||
(await standardOutputTask).Trim();
|
||||
|
||||
string standardError =
|
||||
(await standardErrorTask).Trim();
|
||||
|
||||
string combinedOutput =
|
||||
string.Join(
|
||||
Environment.NewLine,
|
||||
new[]
|
||||
{
|
||||
standardOutput,
|
||||
standardError
|
||||
}
|
||||
.Where(value =>
|
||||
!string.IsNullOrWhiteSpace(value)));
|
||||
|
||||
bool success =
|
||||
process.ExitCode == 0
|
||||
&& combinedOutput.Contains(
|
||||
"OK:ConnectionValidated",
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
&& !combinedOutput.Contains(
|
||||
"ERROR:",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (success)
|
||||
{
|
||||
return CredentialTestResult.Successful();
|
||||
}
|
||||
|
||||
string error =
|
||||
ExtractError(combinedOutput)
|
||||
?? $"Sonic-Verbindungstest fehlgeschlagen, " +
|
||||
$"ExitCode={process.ExitCode}.";
|
||||
|
||||
return CredentialTestResult.Failed(error);
|
||||
}
|
||||
|
||||
private static string? ResolveToolsDirectory()
|
||||
{
|
||||
string[] candidates =
|
||||
[
|
||||
Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
"Tools"),
|
||||
|
||||
Path.Combine(
|
||||
Directory.GetCurrentDirectory(),
|
||||
"Tools")
|
||||
];
|
||||
|
||||
return candidates.FirstOrDefault(
|
||||
directory =>
|
||||
File.Exists(
|
||||
Path.Combine(
|
||||
directory,
|
||||
"SonicMfContainerTool.class")));
|
||||
}
|
||||
|
||||
private static string? ExtractError(
|
||||
string output)
|
||||
{
|
||||
return output
|
||||
.Split(
|
||||
['\r', '\n'],
|
||||
StringSplitOptions.RemoveEmptyEntries)
|
||||
.FirstOrDefault(
|
||||
line =>
|
||||
line.StartsWith(
|
||||
"ERROR:",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
?["ERROR:".Length..]
|
||||
.Trim();
|
||||
}
|
||||
|
||||
private static void TryKill(
|
||||
Process process)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill(
|
||||
entireProcessTree: true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Der ursprüngliche Testfehler bleibt erhalten.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record CredentialTestResult(
|
||||
bool Success,
|
||||
string Message)
|
||||
{
|
||||
public static CredentialTestResult Successful()
|
||||
{
|
||||
return new CredentialTestResult(
|
||||
true,
|
||||
"Sonic-Anmeldung und lesender Containerzugriff waren erfolgreich.");
|
||||
}
|
||||
|
||||
public static CredentialTestResult Failed(
|
||||
string message)
|
||||
{
|
||||
return new CredentialTestResult(
|
||||
false,
|
||||
message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user