cambiado requisito de cabeceras en todas las llamadas y simualcion de datos en la 3 llamada para pruebas

This commit is contained in:
2026-09-09 14:57:46 +02:00
parent 65bde15ea8
commit 5c3c12c02c
3 changed files with 54 additions and 80 deletions

View File

@@ -15,19 +15,13 @@ public sealed class OpeController : ControllerBase
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web); private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
private readonly OpeOptions _options; private readonly OpeOptions _options;
private readonly InternalDenunciasClient _internalApi;
private readonly OpeFieldMapper _fieldMapper;
private readonly ILogger<OpeController> _logger; private readonly ILogger<OpeController> _logger;
public OpeController( public OpeController(
IOptions<OpeOptions> options, IOptions<OpeOptions> options,
InternalDenunciasClient internalApi,
OpeFieldMapper fieldMapper,
ILogger<OpeController> logger) ILogger<OpeController> logger)
{ {
_options = options.Value; _options = options.Value;
_internalApi = internalApi;
_fieldMapper = fieldMapper;
_logger = logger; _logger = logger;
} }
@@ -82,54 +76,25 @@ public sealed class OpeController : ControllerBase
}); });
} }
try // Respuesta temporal de pruebas: no consulta la API interna ni exige
{ // que el expediente exista. FIELD_0 conserva exactamente el valor
var result = await _internalApi.GetFieldsAsync( // recibido y el resto de campos devuelve un valor ficticio.
lookup, _logger.LogInformation(
requestContext.TransactionId, "Respuesta OPE de prueba para el expediente solicitado {Expediente}. TransactionId={TransactionId}",
cancellationToken); identifier,
requestContext.TransactionId);
if (result.Status == InternalLookupStatus.NotFound || result.Fields is null) var testData = new Dictionary<string, OpeFieldValue>(StringComparer.Ordinal)
{ {
return Error( ["FIELD_0"] = new OpeFieldValue("STRING", identifier)
"No se ha encontrado la denuncia o expediente solicitado", };
OpeErrorCauses.ElementNotExists,
null);
}
return Json(_fieldMapper.Map(result.Fields), OpeMediaTypes.GenericOperationResponse); for (var index = 1; index < _options.OutputFields.Count; index++)
}
catch (OperationCanceledException) when (!HttpContext.RequestAborted.IsCancellationRequested)
{ {
_logger.LogWarning( testData[$"FIELD_{index}"] = new OpeFieldValue("STRING", "dato de prueba");
"Timeout consultando ApiDenuncias para una OPE. TransactionId={TransactionId}",
requestContext.TransactionId);
return Error("Error en el conector", OpeErrorCauses.ConnectorError, null);
}
catch (HttpRequestException exception)
{
_logger.LogWarning(
exception,
"No se ha podido conectar con ApiDenuncias. TransactionId={TransactionId}",
requestContext.TransactionId);
return Error("Error en el conector", OpeErrorCauses.ConnectorError, null);
}
catch (InternalApiException exception)
{
_logger.LogWarning(
exception,
"ApiDenuncias ha devuelto una respuesta no utilizable. TransactionId={TransactionId}",
requestContext.TransactionId);
return Error("Error en el conector", OpeErrorCauses.ConnectorError, null);
}
catch (InvalidDataException exception)
{
_logger.LogError(
exception,
"El contrato entre ApiOPE y ApiDenuncias no coincide. TransactionId={TransactionId}",
requestContext.TransactionId);
return Error("Error en el conector", OpeErrorCauses.ConnectorError, null);
} }
return Json(new OpeDataEnvelope(testData), OpeMediaTypes.GenericOperationResponse);
} }
private static ContentResult Error( private static ContentResult Error(

View File

@@ -2,7 +2,6 @@ using System.Security.Claims;
using ApiOPE.Configuration; using ApiOPE.Configuration;
using ApiOPE.Contracts; using ApiOPE.Contracts;
using ApiOPE.Services; using ApiOPE.Services;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
@@ -31,8 +30,7 @@ public sealed class OpeAuthenticationMiddleware
HttpContext context, HttpContext context,
OpeTokenValidator tokenValidator, OpeTokenValidator tokenValidator,
OpeResponseSigner responseSigner, OpeResponseSigner responseSigner,
OpeRequestFileLogger requestFileLogger, OpeRequestFileLogger requestFileLogger)
IOptions<OpeOptions> options)
{ {
var authentication = context.GetEndpoint()?.Metadata.GetMetadata<OpeAuthenticatedAttribute>(); var authentication = context.GetEndpoint()?.Metadata.GetMetadata<OpeAuthenticatedAttribute>();
if (authentication is null) if (authentication is null)
@@ -54,12 +52,6 @@ public sealed class OpeAuthenticationMiddleware
return; return;
} }
if (!ValidateOrganizationHeaders(context.Request.Headers, options.Value, out var organizationFailure))
{
await RejectAsync(context, organizationFailure, requestFileLogger, token, validation.RequestContext);
return;
}
OpeRequestContextStore.Set(context, validation.RequestContext); OpeRequestContextStore.Set(context, validation.RequestContext);
context.User = new ClaimsPrincipal(new ClaimsIdentity( context.User = new ClaimsPrincipal(new ClaimsIdentity(
[ [
@@ -92,6 +84,13 @@ public sealed class OpeAuthenticationMiddleware
validation.RequestContext.TransactionId.ToString(), validation.RequestContext.TransactionId.ToString(),
context.TraceIdentifier, context.TraceIdentifier,
Fingerprint(validation.RequestContext.ClientToken), Fingerprint(validation.RequestContext.ClientToken),
context.Connection.RemoteIpAddress?.ToString(),
ReadHeader(context.Request.Headers, OrganizationIdHeaderName),
ReadHeader(context.Request.Headers, OrganizationDir3HeaderName),
ReadHeader(context.Request.Headers, OrganizationCifHeaderName),
ReadHeader(context.Request.Headers, "Content-Type"),
ReadHeader(context.Request.Headers, "Accept"),
ReadHeader(context.Request.Headers, "User-Agent"),
null)); null));
} }
} }
@@ -118,6 +117,13 @@ public sealed class OpeAuthenticationMiddleware
requestContext?.TransactionId.ToString(), requestContext?.TransactionId.ToString(),
context.TraceIdentifier, context.TraceIdentifier,
string.IsNullOrWhiteSpace(token) ? null : Fingerprint(token), string.IsNullOrWhiteSpace(token) ? null : Fingerprint(token),
context.Connection.RemoteIpAddress?.ToString(),
ReadHeader(context.Request.Headers, OrganizationIdHeaderName),
ReadHeader(context.Request.Headers, OrganizationDir3HeaderName),
ReadHeader(context.Request.Headers, OrganizationCifHeaderName),
ReadHeader(context.Request.Headers, "Content-Type"),
ReadHeader(context.Request.Headers, "Accept"),
ReadHeader(context.Request.Headers, "User-Agent"),
reason)); reason));
await OpeResponseWriter.WriteErrorAsync( await OpeResponseWriter.WriteErrorAsync(
@@ -132,26 +138,10 @@ public sealed class OpeAuthenticationMiddleware
private static string Fingerprint(string value) private static string Fingerprint(string value)
=> Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(value)))[..12]; => Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(value)))[..12];
private static bool ValidateOrganizationHeaders( private static string? ReadHeader(IHeaderDictionary headers, string name)
IHeaderDictionary headers, => headers.TryGetValue(name, out var values) && values.Count > 0
OpeOptions options, ? string.Join(",", values.ToArray()).Trim()
out string failureReason) : null;
{
var valid = MatchesHeader(headers, OrganizationIdHeaderName, options.OrganizationId) &&
MatchesHeader(headers, OrganizationDir3HeaderName, options.OrganizationDir3) &&
MatchesHeader(headers, OrganizationCifHeaderName, options.OrganizationCif);
failureReason = valid
? string.Empty
: "Las cabeceras de organizacion no corresponden al conector configurado.";
return valid;
}
private static bool MatchesHeader(IHeaderDictionary headers, string name, string expected)
{
return TryGetSingleHeader(headers, name, out var value) &&
string.Equals(value, expected, StringComparison.OrdinalIgnoreCase);
}
private static bool TryGetSingleHeader( private static bool TryGetSingleHeader(
IHeaderDictionary headers, IHeaderDictionary headers,

View File

@@ -59,6 +59,13 @@ public sealed record OpeRequestLogEntry(
string? TransactionId, string? TransactionId,
string? RequestId, string? RequestId,
string? ClientTokenFingerprint, string? ClientTokenFingerprint,
string? RemoteIp,
string? OrganizationId,
string? OrganizationDir3,
string? OrganizationCif,
string? ContentType,
string? Accept,
string? UserAgent,
string? FailureReason) string? FailureReason)
{ {
public string ToDisplayLine() public string ToDisplayLine()
@@ -69,8 +76,20 @@ public sealed record OpeRequestLogEntry(
Path, Path,
$"HTTP {StatusCode}", $"HTTP {StatusCode}",
Result, Result,
$"ip={Clean(RemoteIp)}",
$"orgId={Clean(OrganizationId)}",
$"dir3={Clean(OrganizationDir3)}",
$"cif={Clean(OrganizationCif)}",
$"contentType={Clean(ContentType)}",
$"accept={Clean(Accept)}",
$"userAgent={Clean(UserAgent)}",
$"transaccion={TransactionId ?? "-"}", $"transaccion={TransactionId ?? "-"}",
$"peticion={RequestId ?? "-"}", $"peticion={RequestId ?? "-"}",
$"cliente={ClientTokenFingerprint ?? "-"}", $"cliente={ClientTokenFingerprint ?? "-"}",
$"motivo={FailureReason ?? "-"}"); $"motivo={Clean(FailureReason)}");
private static string Clean(string? value)
=> string.IsNullOrWhiteSpace(value)
? "-"
: value.Replace("\r", " ").Replace("\n", " ").Trim();
} }