Skip to content

Commit

Permalink
Add option to log decoded SAMLResponse (#30)
Browse files Browse the repository at this point in the history
 - Add LoggingOptions class with LogDecodedSamlResponse prop (defaults to false)
 - Add SPIDProxyLogging section in appsettings.json
 - Move LogAccess section inside SPIDProxyLogging section
 - Change Configure<T> methods accordingly
 - Add INCOMING_SAML_RESPONSE_DECODED event
  • Loading branch information
fume committed Jul 2, 2022
1 parent 04d1a9e commit ebf3985
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 21 deletions.
34 changes: 19 additions & 15 deletions WebApps/Proxy/Microsoft.SPID.Proxy/Controllers/ProxyController.cs
Expand Up @@ -17,31 +17,34 @@ public class ProxyController : Controller
private readonly IFederatorRequestService _federatorRequestService;
private readonly FederatorOptions _federatorOptions;
private readonly TechnicalChecksOptions _technicalChecksOptions;
private readonly LoggingOptions _loggingOptions;

public ProxyController(ILogger<ProxyController> logger,
ILogAccessService logAccessService,
IFederatorResponseService federatorResponseService,
IFederatorRequestService federatorRequestService,
IOptions<FederatorOptions> federatorOptions,
IOptions<TechnicalChecksOptions> technicalChecksOptions)
IOptions<TechnicalChecksOptions> technicalChecksOptions,
IOptions<LoggingOptions> loggingOptions)
{
_logger = logger;
_logAccessService = logAccessService;
_federatorResponseService = federatorResponseService;
_federatorRequestService = federatorRequestService;
_federatorOptions = federatorOptions.Value;
_technicalChecksOptions = technicalChecksOptions.Value;
_loggingOptions = loggingOptions.Value;
}

[HttpGet]
[Route("proxy/index/{identityProvider}")]
public async Task<IActionResult> Index(string identityProvider)
{
_logger.LogInformation(LoggingEvents.PROXY_INDEX_INVOKED, "Proxy/Index endpoint invoked. IdentityProvider = {identityProvider}, RequestUrl = {requestUrl}", identityProvider, HttpContext.Request.GetDisplayUrl());

if (string.IsNullOrWhiteSpace(identityProvider))
{
_logger.LogError(LoggingEvents.ERROR_IDENTITYPROVIDER_EMPTY,$"{nameof(identityProvider)} is null or empty. Impossible to continue processing");
_logger.LogError(LoggingEvents.ERROR_IDENTITYPROVIDER_EMPTY, $"{nameof(identityProvider)} is null or empty. Impossible to continue processing");
throw new ArgumentException("Parameter cannot be null or empty", nameof(identityProvider));
}

Expand All @@ -63,7 +66,7 @@ public async Task<IActionResult> Index(string identityProvider)
}
catch (Exception e)
{
_logger.LogError(LoggingEvents.ERROR_DECODE_SAML_REQUEST,e, "Unable to decode SAMLRequest.");
_logger.LogError(LoggingEvents.ERROR_DECODE_SAML_REQUEST, e, "Unable to decode SAMLRequest.");
return BadRequest();
}

Expand All @@ -87,7 +90,7 @@ public async Task<IActionResult> Index(string identityProvider)
}
else
{
_logger.LogError(LoggingEvents.ERROR_NO_SAML_QUERYSTRING,"The request doesn't have SAML mandatory parameters such as SAMLRequest. Returning BadRequest");
_logger.LogError(LoggingEvents.ERROR_NO_SAML_QUERYSTRING, "The request doesn't have SAML mandatory parameters such as SAMLRequest. Returning BadRequest");
return BadRequest();
}
}
Expand All @@ -103,21 +106,22 @@ public async Task<ActionResult> AssertionConsumer(string SAMLResponse, string Re
{
_logger.LogInformation(LoggingEvents.ASSERTION_CONSUMER_INVOKED, "AssertionConsumer endpoint invoked. SAMLResponse = {samlResponse}, RelayState = {relayState}", SAMLResponse, RelayState);

string inResponseTo, id, issuer;
string inResponseTo, id, issuer, decodedSamlResponse;
XmlDocument responseXml;

try
{
responseXml = SAMLResponse
.DecodeSamlResponse()
.ToXmlDocument();

_logger.LogDebug("SAMLResponse decoded.");
decodedSamlResponse = SAMLResponse.DecodeSamlResponse();
responseXml = decodedSamlResponse.ToXmlDocument();

if (_loggingOptions.LogDecodedSamlResponse)
_logger.LogInformation(LoggingEvents.INCOMING_SAML_RESPONSE_DECODED, "SAMLResponse decoded = {samlResponseDecoded}", decodedSamlResponse);
else
_logger.LogInformation(LoggingEvents.INCOMING_SAML_RESPONSE_DECODED, "SAMLResponse decoded.");
}
catch (Exception e)
{
_logger.LogError(LoggingEvents.ERROR_DECODE_SAML_RESPONSE,e, "An error occurred decoding the SAMLResponse");
_logger.LogError(LoggingEvents.ERROR_DECODE_SAML_RESPONSE, e, "An error occurred decoding the SAMLResponse");
throw;
}

Expand All @@ -141,7 +145,7 @@ public async Task<ActionResult> AssertionConsumer(string SAMLResponse, string Re
{
UserFriendlyMessage = new HtmlString("Signature della risposta non valida o non presente, impossibile proseguire con l'autenticazione.")
};
_logger.LogError(LoggingEvents.ERROR_INVALID_SAML_RESPONSE_SIGNATURE,"Invalid SAMLResponse Signature");
_logger.LogError(LoggingEvents.ERROR_INVALID_SAML_RESPONSE_SIGNATURE, "Invalid SAMLResponse Signature");
return View("CourtesyPage", errorModel);
}
_logger.LogInformation(LoggingEvents.SAML_RESPONSE_SIGNATURE_VALIDATED, "SAMLResponse signature validated");
Expand Down Expand Up @@ -179,12 +183,12 @@ public async Task<ActionResult> AssertionConsumer(string SAMLResponse, string Re
}
catch (SPIDValidationException spidEx)
{
_logger.LogError(LoggingEvents.ERROR_SAML_RESPONSE_VALIDATION_FAILED,spidEx, "SPID SAMLResponse validation failed");
_logger.LogError(LoggingEvents.ERROR_SAML_RESPONSE_VALIDATION_FAILED, spidEx, "SPID SAMLResponse validation failed");
throw;
}
catch (Exception ex)
{
_logger.LogError(LoggingEvents.ERROR_ASSERTION_CONSUMER_GENERIC_ERROR,ex, "An error occurred on the AssertionConsumer endpoint.");
_logger.LogError(LoggingEvents.ERROR_ASSERTION_CONSUMER_GENERIC_ERROR, ex, "An error occurred on the AssertionConsumer endpoint.");
throw;
}
}
Expand Down
2 changes: 2 additions & 0 deletions WebApps/Proxy/Microsoft.SPID.Proxy/Models/LoggingEvents.cs
Expand Up @@ -15,6 +15,8 @@ public static class LoggingEvents
public const int OUTGOING_SAML_REQUEST_CREATED = 5004;
public const int USER_LOGGED_IN = 5005;
public const int PROXY_INDEX_INVOKED = 5006;
public const int INCOMING_SAML_RESPONSE_DECODED = 5007;


//Errors
public const int ERROR_IDENTITYPROVIDER_EMPTY = 9000;
Expand Down
@@ -0,0 +1,7 @@
namespace Microsoft.SPID.Proxy.Models.Options
{
public class LoggingOptions
{
public bool LogDecodedSamlResponse { get; set; } = false;
}
}
7 changes: 5 additions & 2 deletions WebApps/Proxy/Microsoft.SPID.Proxy/Program.cs
Expand Up @@ -36,11 +36,14 @@
builder.Services.Configure<CustomErrorOptions>(options => builder.Configuration.GetSection("customErrors").Bind(options));
builder.Services.Configure<FederatorOptions>(options => builder.Configuration.GetSection("Federator").Bind(options));
builder.Services.Configure<IDPMetadatasOptions>(options => builder.Configuration.GetSection("idpMetadatas").Bind(options));
builder.Services.Configure<LogAccessOptions>(options => builder.Configuration.GetSection("LogAccess").Bind(options));
builder.Services.Configure<LogAccessOptions>(options => options.FieldsToLog = builder.Configuration.GetValue<string>("LogAccess:FieldsToLog").Split(",").ToList());
builder.Services.Configure<LogAccessOptions>(options => {
builder.Configuration.GetSection("SPIDProxyLogging:LogAccess").Bind(options);
options.FieldsToLog = builder.Configuration.GetValue<string>("SPIDProxyLogging:LogAccess:FieldsToLog").Split(",").ToList();
});
builder.Services.Configure<SPIDOptions>(options => builder.Configuration.GetSection("spid").Bind(options));
builder.Services.Configure<TechnicalChecksOptions>(options => builder.Configuration.GetSection("TechnicalChecks").Bind(options));
builder.Services.Configure<EventLogSettings>(options => builder.Configuration.GetSection("Logging:EventLog:Settings").Bind(options));
builder.Services.Configure<LoggingOptions>(options => builder.Configuration.GetSection("SPIDProxyLogging").Bind(options));

builder.Services
.AddMvc()
Expand Down
11 changes: 7 additions & 4 deletions WebApps/Proxy/Microsoft.SPID.Proxy/appsettings.json
Expand Up @@ -32,10 +32,6 @@
"webpages:Enabled": false,
"ClientValidationEnabled": true,
"UnobtrusiveJavaScriptEnabled": true,
"LogAccess": {
"Enabled": true,
"FieldsToLog": "fiscalNumber,email,name,familyName"
},
"Certificate": {
"CertName": "YourPfxName.pfx",
"CertPassword": "YourPfxPassword"
Expand Down Expand Up @@ -161,5 +157,12 @@
"sp-proxy.eid.gov.it/spproxy/idpit": "https://sp-proxy.eid.gov.it/spproxy/idpitmetadata"
},
"CacheAbsoluteExpirationInMins": 120
},
"SPIDProxyLogging": {
"LogDecodedSamlResponse": false,
"LogAccess": {
"Enabled": true,
"FieldsToLog": "fiscalNumber,email,name,familyName,spidCode"
}
}
}

0 comments on commit ebf3985

Please sign in to comment.