From aeb34bddbcbf61e94290386f4f56dcfb5b6c474a Mon Sep 17 00:00:00 2001 From: Thomas Nymand Date: Wed, 1 Jul 2026 19:32:28 +0200 Subject: [PATCH 1/2] REF-11 Ignore non-metadata files in the metadata directory (#25) ParseFile returns null for a file that is not SAML 2.0 metadata, but HandleCreateIdp/HandleUpdateIdp dereferenced the result immediately, throwing a NullReferenceException that aborted configuration loading (e.g. when a README is placed in the metadata directory). Skip such files gracefully; ParseFile already traces why the file was rejected. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XFEHBfb5PM63Qi8idztJYG --- .../dk.nita.saml20/Config/SAML20FederationConfig.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dk.nita.saml20/dk.nita.saml20/Config/SAML20FederationConfig.cs b/src/dk.nita.saml20/dk.nita.saml20/Config/SAML20FederationConfig.cs index 59797ac..dc9a025 100644 --- a/src/dk.nita.saml20/dk.nita.saml20/Config/SAML20FederationConfig.cs +++ b/src/dk.nita.saml20/dk.nita.saml20/Config/SAML20FederationConfig.cs @@ -479,6 +479,8 @@ private void HandleDeleteIdp(string filename) private void HandleUpdateIdp(string filename) { var metadataDoc = ParseFile(filename); + if (metadataDoc == null) + return; // Not a SAML 2.0 metadata file - ignore it instead of failing. // First we try and find the endpoint based on the entity id in the metadata var endp = FindEndPoint(metadataDoc.EntityId); if (endp == null && _fileToEntity.ContainsKey(filename)) @@ -501,6 +503,8 @@ private void HandleCreateIdp(string filename) if (!_fileToEntity.ContainsKey(filename)) { var metadataDoc = ParseFile(filename); + if (metadataDoc == null) + return; // Not a SAML 2.0 metadata file (e.g. a README placed in the metadata directory) - ignore it instead of failing. var endp = FindEndPoint(metadataDoc.EntityId); if (endp == null) // If the endpoint does not exist, create it. { From 2788aad3df124ca6758da63ab78858586d3e3408 Mon Sep 17 00:00:00 2001 From: Thomas Nymand Date: Wed, 1 Jul 2026 19:32:28 +0200 Subject: [PATCH 2/2] REF-11 Give a clear error when the default IDPEndpoint id is misspelled (#24) A misspelled id on a configured IDPEndpoint means no metadata file matches it, leaving metadata null. When such an endpoint was selected as the default, RetrieveIDP returned it and the caller hit an opaque NullReferenceException. Throw a descriptive Saml20Exception naming the id instead. Reuses the previously unused MetadataNotFound resource, reworded to point at the likely misspelling. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XFEHBfb5PM63Qi8idztJYG --- .../dk.nita.saml20/Properties/Resources.Designer.cs | 2 +- src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.resx | 2 +- .../Protocol/Saml20AbstractEndpointHandler.cs | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.Designer.cs b/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.Designer.cs index 773e8db..3d26388 100644 --- a/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.Designer.cs +++ b/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.Designer.cs @@ -755,7 +755,7 @@ internal static string MetadataLocationNotFound { } /// - /// Looks up a localized string similar to Metadata not found for idp endpoint with id {0}. + /// Looks up a localized string similar to No metadata was found for the configured IDPEndpoint with id "{0}". Verify that the id matches the entityID of a metadata file in the configured metadata directory (a misspelled id is the most common cause). /// internal static string MetadataNotFound { get { diff --git a/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.resx b/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.resx index 6a2b119..a84c466 100644 --- a/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.resx +++ b/src/dk.nita.saml20/dk.nita.saml20/Properties/Resources.resx @@ -334,7 +334,7 @@ AppID={1} The specified metadata directory "{0}" could not be located. - Metadata not found for idp endpoint with id {0} + No metadata was found for the configured IDPEndpoint with id "{0}". Verify that the id matches the entityID of a metadata file in the configured metadata directory (a misspelled id is the most common cause). Xml error: attribute {0} of element {1}: {2} must have a value. diff --git a/src/dk.nita.saml20/dk.nita.saml20/Protocol/Saml20AbstractEndpointHandler.cs b/src/dk.nita.saml20/dk.nita.saml20/Protocol/Saml20AbstractEndpointHandler.cs index 9e65c3c..7e16f56 100644 --- a/src/dk.nita.saml20/dk.nita.saml20/Protocol/Saml20AbstractEndpointHandler.cs +++ b/src/dk.nita.saml20/dk.nita.saml20/Protocol/Saml20AbstractEndpointHandler.cs @@ -9,6 +9,7 @@ using dk.nita.saml20.Properties; using dk.nita.saml20.Schema.Protocol; using dk.nita.saml20.Utils; +using Saml2.Properties; using Trace = dk.nita.saml20.Utils.Trace; namespace dk.nita.saml20.protocol @@ -142,6 +143,11 @@ public IDPEndPoint RetrieveIDP(HttpContext context) var defaultIdp = config.Endpoints.IDPEndPoints.Find(idp => idp.Default); if (defaultIdp != null) { + // A configured endpoint has no metadata when no metadata file matches its id (typically a misspelled + // id). Fail with a clear message instead of the opaque NullReferenceException that follows downstream. + if (defaultIdp.metadata == null) + throw new Saml20Exception(string.Format(Resources.MetadataNotFound, defaultIdp.Id)); + if (Trace.ShouldTrace(TraceEventType.Information)) Trace.TraceData(TraceEventType.Information, "Using IdP marked as default: " + defaultIdp.Id);