Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions Auth/AuthResponseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
using Fiscalapi.XmlDownloader.Common;
using Fiscalapi.XmlDownloader.Common.Enums;
using Fiscalapi.XmlDownloader.Common.Http;
using Microsoft.Extensions.Logging;

namespace Fiscalapi.XmlDownloader.Auth;

public static class AuthResponseService
{
public static AuthResponse Build(SatResponse satResponse, ICredential credential)
public static AuthResponse Build(SatResponse satResponse, ICredential credential, ILogger logger)
{
/*
*<s:envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
Expand Down Expand Up @@ -56,24 +57,54 @@ public static AuthResponse Build(SatResponse satResponse, ICredential credential
if (satResponse.IsSuccessStatusCode)
{
var envelope = XmlSerializerService.Deserialize<AuthEnvelope>(satResponse.RawResponse!);
return new AuthResponse
var tokenValue = envelope?.Body?.AutenticaResponse?.AutenticaResult;

var authResponse = new AuthResponse
{
Succeeded = true,
SatStatus = SatStatus.RequestSucceeded,
SatStatusCode = SatStatus.RequestSucceeded.ToEnumCode(),
SatMessage = "",
TokenValue = envelope?.Body?.AutenticaResponse?.AutenticaResult,
TokenValue = tokenValue,
ValidFrom = envelope?.Header?.Security?.Timestamp?.Created,
ValidTo = envelope?.Header?.Security?.Timestamp?.Expires,
RawRequest = satResponse.RawRequest,
RawResponse = satResponse.RawResponse,
Tin = credential.Certificate.Rfc
};

// Critical logging: Verify token was received
if (string.IsNullOrWhiteSpace(tokenValue))
{
logger.LogWarning(
"Authentication succeeded but token is missing. RFC: {Rfc}, HasEnvelope: {HasEnvelope}, HasBody: {HasBody}, HasAutenticaResponse: {HasAutenticaResponse}",
credential.Certificate.Rfc,
envelope != null,
envelope?.Body != null,
envelope?.Body?.AutenticaResponse != null);
}
else
{
logger.LogInformation(
"Authentication succeeded. RFC: {Rfc}, TokenLength: {TokenLength}, ValidFrom: {ValidFrom}, ValidTo: {ValidTo}",
credential.Certificate.Rfc,
tokenValue.Length,
authResponse.ValidFrom,
authResponse.ValidTo);
}

return authResponse;
}

if (satResponse.RawResponse is not null && satResponse.RawResponse.ToLowerInvariant().Contains("fault"))
{
var faultEnvelope = XmlSerializerService.Deserialize<AuthFaultEnvelope>(satResponse.RawResponse);
logger.LogError(
"Authentication failed with SOAP fault. RFC: {Rfc}, FaultCode: {FaultCode}, FaultMessage: {FaultMessage}",
credential.Certificate.Rfc,
faultEnvelope?.Body?.Fault?.FaultCode,
faultEnvelope?.Body?.Fault?.FaultMessage);

return new AuthResponse
{
Succeeded = false,
Expand All @@ -85,6 +116,12 @@ public static AuthResponse Build(SatResponse satResponse, ICredential credential
};
}

logger.LogError(
"Authentication failed with unexpected status. RFC: {Rfc}, HttpStatusCode: {StatusCode}, ReasonPhrase: {ReasonPhrase}",
credential.Certificate.Rfc,
satResponse.HttpStatusCode,
satResponse.ReasonPhrase);

return new AuthResponse
{
Succeeded = false,
Expand Down
99 changes: 77 additions & 22 deletions Auth/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Fiscalapi.XmlDownloader.Auth.Models;
using Fiscalapi.XmlDownloader.Common;
using Fiscalapi.XmlDownloader.Common.Http;
using Microsoft.Extensions.Logging;

namespace Fiscalapi.XmlDownloader.Auth;

Expand All @@ -28,33 +29,87 @@ namespace Fiscalapi.XmlDownloader.Auth;
public class AuthService : SatService, IAuthService
{
/// <summary>
/// Authenticates with SAT using the provided credential and returns the authentication token
/// Constructor for dependency injection scenarios
/// </summary>
public async Task<AuthResponse> AuthenticateAsync(ICredential credential,
CancellationToken cancellationToken = default)
/// <param name="httpClient">HttpClient instance</param>
/// <param name="logger">Logger instance</param>
public AuthService(HttpClient httpClient, ILogger<AuthService> logger)
: base(httpClient, logger)
{
// Generate Sat XML security token ID
var uuid = CreateSecurityToken();

// Create digest and signature using unified template
var digest = CreateDigest(credential);
var signature = CreateSignature(digest, credential, uuid);

// Build SOAP envelope
var authXml = BuildEnvelope(digest, uuid, credential.Certificate.RawDataBytes.ToBase64String(),
signature);
}

// Send request
var satResponse = await SendRequestAsync(
url: SatUrl.AuthUrl,
action: SatUrl.AuthAction,
payload: authXml,
cancellationToken: cancellationToken);
/// <summary>
/// Constructor for direct instantiation scenarios
/// </summary>
/// <param name="logger">Logger instance</param>
public AuthService(ILogger<AuthService> logger)
: base(logger)
{
}

// Map response
var authResponse = AuthResponseService.Build(satResponse, credential);
/// <summary>
/// Authenticates with SAT using the provided credential and returns the authentication token
/// </summary>
public async Task<AuthResponse> AuthenticateAsync(ICredential credential,
ILogger logger, CancellationToken cancellationToken = default)
{
logger.LogInformation("Starting SAT authentication process for RFC: {Rfc}", credential.Certificate.Rfc);

return authResponse;
try
{
// Generate Sat XML security token ID
var uuid = CreateSecurityToken();
logger.LogDebug("Generated security token UUID: {Uuid}", uuid);

// Create digest and signature using unified template
var digest = CreateDigest(credential);
var signature = CreateSignature(digest, credential, uuid);

// Build SOAP envelope
var authXml = BuildEnvelope(digest, uuid, credential.Certificate.RawDataBytes.ToBase64String(),
signature);

// Send request
logger.LogInformation("Sending authentication request to SAT. URL: {Url}", SatUrl.AuthUrl);
var satResponse = await SendRequestAsync(
url: SatUrl.AuthUrl,
action: SatUrl.AuthAction,
payload: authXml,
cancellationToken: cancellationToken);

logger.LogInformation("SAT authentication response received. Success: {IsSuccessStatusCode}, Status: {StatusCode}",
satResponse.IsSuccessStatusCode,
satResponse.HttpStatusCode);

// Log complete XML response for debugging
if (!satResponse.IsSuccessStatusCode || string.IsNullOrWhiteSpace(satResponse.RawResponse))
{
logger.LogError(
"SAT authentication failed. RFC: {Rfc}, StatusCode: {StatusCode}, ReasonPhrase: {ReasonPhrase}, RawResponse: {RawResponse}",
credential.Certificate.Rfc,
satResponse.HttpStatusCode,
satResponse.ReasonPhrase,
satResponse.RawResponse ?? "[Empty Response]");
}
else
{
logger.LogDebug(
"SAT authentication raw response XML. RFC: {Rfc}, ResponseLength: {Length}, RawResponse: {RawResponse}",
credential.Certificate.Rfc,
satResponse.RawResponse?.Length ?? 0,
satResponse.RawResponse);
}

// Map response
var authResponse = AuthResponseService.Build(satResponse, credential, logger);

return authResponse;
}
catch (Exception ex)
{
logger.LogError(ex, "Error during SAT authentication process for RFC: {Rfc}", credential.Certificate.Rfc);
throw;
}
}

/// <summary>
Expand Down
4 changes: 3 additions & 1 deletion Auth/IAuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

using Fiscalapi.Credentials.Core;
using Fiscalapi.XmlDownloader.Auth.Models;
using Microsoft.Extensions.Logging;

namespace Fiscalapi.XmlDownloader.Auth;

Expand All @@ -29,6 +30,7 @@ public interface IAuthService
/// </summary>
/// <param name="credential"></param>
/// <param name="cancellationToken">CancellationToken</param>
/// <param name="logger">Logger</param>
/// <returns></returns>
Task<AuthResponse> AuthenticateAsync(ICredential credential, CancellationToken cancellationToken = default);
Task<AuthResponse> AuthenticateAsync(ICredential credential, ILogger logger, CancellationToken cancellationToken = default);
}
28 changes: 17 additions & 11 deletions Common/Http/SatService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

using System.Net;
using System.Text;
using Microsoft.Extensions.Logging;

namespace Fiscalapi.XmlDownloader.Common.Http;

Expand All @@ -26,25 +27,28 @@ public abstract class SatService : IDisposable
{
private readonly HttpClient _httpClient;
private readonly bool _ownsHttpClient;
private readonly ILogger _logger;
private bool _disposed;

protected bool IsDebugEnabled { get; set; }

/// <summary>
/// Constructor for dependency injection scenarios
/// </summary>
protected SatService(HttpClient httpClient)
protected SatService(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_ownsHttpClient = false;
}

/// <summary>
/// Constructor for direct instantiation scenarios
/// </summary>
protected SatService()
protected SatService(ILogger logger)
{
_httpClient = new HttpClient();
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_ownsHttpClient = true;
}

Expand Down Expand Up @@ -100,6 +104,8 @@ protected async Task<SatResponse> SendRequestAsync(string url, string action, st
{
if (IsDebugEnabled)
LogError(ex, url, action);

_logger.LogError(ex, "Error sending SOAP request to {Url} with action {Action}", url, action);

return new SatResponse
{
Expand All @@ -118,7 +124,7 @@ protected async Task<SatResponse> SendRequestAsync(string url, string action, st
/// <param name="url">Request URL</param>
/// <param name="soapAction">SOAP action header</param>
/// <param name="payload">Request payload</param>
private static void LogRequest(HttpRequestMessage request, string url, string soapAction, string payload)
private void LogRequest(HttpRequestMessage request, string url, string soapAction, string payload)
{
try
{
Expand Down Expand Up @@ -150,11 +156,11 @@ private static void LogRequest(HttpRequestMessage request, string url, string so
sb.AppendLine(payload);
sb.AppendLine("=== END REQUEST ===");

Console.WriteLine(sb.ToString());
_logger.LogDebug(sb.ToString());
}
catch (Exception ex)
{
Console.WriteLine($"Error logging request: {ex.Message}");
_logger.LogError(ex, "Error logging request");
}
}

Expand All @@ -165,7 +171,7 @@ private static void LogRequest(HttpRequestMessage request, string url, string so
/// <param name="responseContent">Response content</param>
/// <param name="url">Original request URL</param>
/// <param name="soapAction">Original SOAP action</param>
private static void LogResponse(HttpResponseMessage response, string responseContent, string url,
private void LogResponse(HttpResponseMessage response, string responseContent, string url,
string soapAction)
{
try
Expand Down Expand Up @@ -200,11 +206,11 @@ private static void LogResponse(HttpResponseMessage response, string responseCon
sb.AppendLine(string.IsNullOrEmpty(responseContent) ? "[Empty Response]" : responseContent);
sb.AppendLine("=== END RESPONSE ===");

Console.WriteLine(sb.ToString());
_logger.LogDebug(sb.ToString());
}
catch (Exception ex)
{
Console.WriteLine($"Error logging response: {ex.Message}");
_logger.LogError(ex, "Error logging response");
}
}

Expand All @@ -214,7 +220,7 @@ private static void LogResponse(HttpResponseMessage response, string responseCon
/// <param name="ex">Exception that occurred</param>
/// <param name="url">Request URL</param>
/// <param name="soapAction">SOAP action</param>
private static void LogError(Exception ex, string url, string soapAction)
private void LogError(Exception ex, string url, string soapAction)
{
try
{
Expand All @@ -235,11 +241,11 @@ private static void LogError(Exception ex, string url, string soapAction)
sb.AppendLine(ex.StackTrace);
sb.AppendLine("=== END ERROR ===");

Console.WriteLine(sb.ToString());
_logger.LogError(sb.ToString());
}
catch (Exception logEx)
{
Console.WriteLine($"Error logging exception: {logEx.Message}");
_logger.LogError(logEx, "Error logging exception");
}
}

Expand Down
3 changes: 2 additions & 1 deletion Download/DownloadResponseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
using Fiscalapi.XmlDownloader.Common.Http;
using Fiscalapi.XmlDownloader.Download.Models;
using Fiscalapi.XmlDownloader.Download.Models.Sat;
using Microsoft.Extensions.Logging;

namespace Fiscalapi.XmlDownloader.Download;

public static class DownloadResponseService
{
public static DownloadResponse Build(SatResponse satResponse)
public static DownloadResponse Build(SatResponse satResponse, ILogger logger)
{
if (satResponse.IsSuccessStatusCode)
{
Expand Down
Loading