Sustainsys / Saml2

Saml2 Authentication services for ASP.NET
Other
956 stars 602 forks source link

Problem with reading metadata file #1418

Closed yaronbsmtx closed 9 months ago

yaronbsmtx commented 10 months ago

Hi,

We are using version 2.9.1 of the library in a development environment that has restricted internet access. We developed a backend using .NET 6 and everything worked just fine up until a few weeks ago. During this period we were engaged in other activities but when we came back to restart development revolving around SAML authentication on the same machine, we started getting some errors.

This is the exception we get:

System.Xml.XmlException: CData elements not valid at top level of an XML document. Line 1, position 3. at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, XmlException exception) at System.Xml.XmlUTF8TextReader.Read() at Sustainsys.Saml2.Metadata.FilteringXmlDictionaryReader.Read() at System.Xml.XmlReader.MoveToContent() at System.Xml.XmlReader.IsStartElement(String localname, String ns) at Sustainsys.Saml2.Metadata.MetadataSerializer.ReadMetadataCore(XmlReader reader, SecurityTokenResolver tokenResolver) at Sustainsys.Saml2.Metadata.MetadataSerializer.ReadMetadata(XmlReader reader, SecurityTokenResolver tokenResolver) at Sustainsys.Saml2.Metadata.MetadataSerializer.ReadMetadata(XmlReader reader) at Sustainsys.Saml2.Metadata.MetadataLoader.Load(XmlDictionaryReader reader) at Sustainsys.Saml2.Metadata.MetadataLoader.Load(String metadataLocation, IEnumerable`1 signingKeys, Boolean validateCertificate, String minIncomingSigningAlgorithm) at Sustainsys.Saml2.Metadata.MetadataLoader.LoadIdp(String metadataLocation, Boolean unpackEntitiesDescriptor) at Sustainsys.Saml2.IdentityProvider.DoLoadMetadata() at Sustainsys.Saml2.IdentityProvider.set_LoadMetadata(Boolean value) at Microsoft.Extensions.DependencyInjection.MTXApiServiceCollection.<>cDisplayClass0_0.b3(Saml2Options options) in C:\\MTXApiServiceCollection.cs:line 112 at Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure(String name, TOptions options) at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name) at Sustainsys.Saml2.AspNetCore2.Saml2Handler.<>cDisplayClass7_0.b0() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at System.Lazy`1.get_Value() at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions) at Sustainsys.Saml2.AspNetCore2.Saml2Handler.InitializeAsync(AuthenticationScheme scheme, HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, String authenticationScheme) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited ...

This is the metadata file (sensitive information was removed/changed):

\<?xml version="1.0" encoding="UTF-8" ?> \<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="I3fe16780e7705b9" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds=" http://www.w3.org/2000/09/xmldsig#" entityID=" https://portal-api-test.mtx.com/bigip"> \ \ \ \ \base_64_certificate</ds:X509Certificate> \</ds:X509Data> \</ds:KeyInfo> \ \<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location=" https://portal-api-test.mtx.com/saml/idp/profile/post/sls" ResponseLocation=" https://portal-api-test.mtx.com/saml/idp/profile/post/slr"> \ \<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location=" https://portal-api-test.mtx.com/saml/idp/profile/redirect/sls" ResponseLocation=" https://portal-api-test.mtx.com/saml/idp/profile/redirect/slr"> \ \urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified \ \ \ \ \ \</saml:Attribute> \ \

And this is the relevant code snippet:

services.AddAuthentication(options => { options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = Saml2Defaults.Scheme; options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddSaml2(options => { bool isEnc = config.GetValue("GeneralSettings:isEnc"); string cerificate = config.GetValue("SAML:Certificate"); string tempSecret = config.GetValue("SAML:Secret"); string secret = isEnc ? encryptionService.Decrypt(tempSecret) : tempSecret; string metadata = config.GetValue("SAML:Metadata"); string baseUrl = config.GetValue("SAML:BaseUrl"); options.SPOptions.EntityId = new EntityId(baseUrl); options.SPOptions.ReturnUrl = new Uri(baseUrl + "/Acs");
options.SPOptions.ServiceCertificates.Add(new ServiceCertificate { Certificate = new X509Certificate2(@cerificate, secret), Use = CertificateUse.Both, Status = CertificateStatus.Current, }); var idp = new IdentityProvider(new EntityId(baseUrl + "/bigip"), options.SPOptions) { Binding = Saml2BindingType.HttpPost, LoadMetadata = true, AllowUnsolicitedAuthnResponse = true, MetadataLocation = @metadata, SingleSignOnServiceUrl = new Uri(baseUrl + "/saml/idp/profile/redirectorpost/sso"), SingleLogoutServiceBinding = Saml2BindingType.HttpRedirect, SingleLogoutServiceUrl = new Uri(baseUrl + "/saml/idp/profile/redirect/sls"), SingleLogoutServiceResponseUrl = new Uri(baseUrl + "/saml/idp/profile/redirect/slr"), DisableOutboundLogoutRequests = false, }; options.IdentityProviders.Add(idp); }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);

Any ideas would be welcome.

AndersAbel commented 10 months ago

It looks like the metadata that was read is different from the one you posted. This can sometimes happen when there is a temporary server issue on the Identity Provider. If an error page is shown, the metadata parser tries to treat it and read it as XML which fails.

yaronbsmtx commented 10 months ago

Currently the issue was circumvented by trying another server (with a fresh configuration) where everything works just fine. I assume you mean the metadata sent by the IdP over the wire is either different than what is stored in the XML file on our backend server or we somehow receive something that is not an XML response at all. We will check this if and when we encounter this issue again with a different backend server.

AndersAbel commented 10 months ago

I've seen this in the past when a server return an error page. When the XML parser tries to read HTML it reports the CDATA error.