diff --git a/.gitignore b/.gitignore
index dfcfd56..00aedca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,8 @@ bld/
# Visual Studio 2015/2017 cache/options directory
.vs/
+# Visual Studio Code options directory
+.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Extensions/CieExtensions.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Extensions/CieExtensions.cs
index 4e599cf..a85bb18 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Extensions/CieExtensions.cs
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Extensions/CieExtensions.cs
@@ -10,6 +10,7 @@
using System;
using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
+using CIE.AspNetCore.Authentication.Models.ServiceProviders;
namespace CIE.AspNetCore.Authentication.Extensions
{
@@ -21,7 +22,26 @@ public static class CieExtensions
///
///
public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, IConfiguration configuration)
- => builder.AddCie(CieDefaults.AuthenticationScheme, configuration, _ => { });
+ => builder.AddCie(CieDefaults.AuthenticationScheme, o => { o.LoadFromConfiguration(configuration); });
+
+ ///
+ /// Registers the using the default authentication scheme, display name, and the given options configuration.
+ ///
+ ///
+ /// A delegate that configures the .
+ ///
+ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, Action configureOptions)
+ => builder.AddCie(CieDefaults.AuthenticationScheme, configureOptions);
+
+ ///
+ /// Registers the using the given authentication scheme, default display name, and the given options configuration.
+ ///
+ ///
+ ///
+ /// A delegate that configures the .
+ ///
+ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions)
+ => builder.AddCie(authenticationScheme, CieDefaults.DisplayName, configureOptions);
///
/// Registers the using the default authentication scheme, display name, and the given options configuration.
@@ -29,9 +49,10 @@ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, I
///
/// A delegate that configures the .
///
+ /*
public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, IConfiguration configuration, Action configureOptions)
=> builder.AddCie(CieDefaults.AuthenticationScheme, configuration, configureOptions);
-
+ */
///
/// Registers the using the given authentication scheme, default display name, and the given options configuration.
///
@@ -39,8 +60,10 @@ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, I
///
/// A delegate that configures the .
///
+ /*
public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, string authenticationScheme, IConfiguration configuration, Action configureOptions)
=> builder.AddCie(authenticationScheme, CieDefaults.DisplayName, configuration, configureOptions);
+ */
///
/// Registers the using the given authentication scheme, display name, and options configuration.
@@ -50,6 +73,31 @@ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, s
///
/// A delegate that configures the .
///
+ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions)
+ {
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, CiePostConfigureOptions>());
+ builder.Services.TryAdd(ServiceDescriptor.Singleton());
+ builder.Services.AddHttpClient("cie");
+ builder.Services.TryAddScoped(factory =>
+ {
+ var actionContext = factory.GetService().ActionContext;
+ var urlHelperFactory = factory.GetService();
+ return urlHelperFactory.GetUrlHelper(actionContext);
+ });
+ builder.Services.AddOptions().Configure(configureOptions);
+ builder.Services.TryAddScoped();
+ return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions);
+ }
+
+ ///
+ /// Registers the using the given authentication scheme, display name, and options configuration.
+ ///
+ ///
+ ///
+ ///
+ /// A delegate that configures the .
+ ///
+ /*
public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, IConfiguration configuration, Action configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, CiePostConfigureOptions>());
@@ -64,8 +112,16 @@ public static AuthenticationBuilder AddCie(this AuthenticationBuilder builder, s
builder.Services.AddOptions().Configure(o => OptionsHelper.LoadFromConfiguration(o, configuration));
return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions);
}
+ */
+
+ public static AuthenticationBuilder AddServiceProvidersFactory(this AuthenticationBuilder builder)
+ where T : class, IServiceProvidersFactory
+ {
+ builder.Services.AddScoped();
+ return builder;
+ }
- public static IApplicationBuilder AddSpidSPMetadataEndpoints(this IApplicationBuilder builder)
+ public static IApplicationBuilder AddCieSPMetadataEndpoints(this IApplicationBuilder builder)
{
return builder.UseMiddleware();
}
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/CieOptions.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/CieOptions.cs
index dc81317..448bfcd 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/CieOptions.cs
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/CieOptions.cs
@@ -20,7 +20,7 @@ public CieOptions()
// In AAD it sends the cleanup message to a random Reply Url and there's no deterministic way to configure it.
// If you manage to get it configured, then you can set RemoteSignOutPath accordingly.
RemoteSignOutPath = "/signout-cie";
- ServiceProvidersMetadataEndpointsBasePath = "/metadata-spid";
+ ServiceProvidersMetadataEndpointsBasePath = "/metadata-cie";
Events = new CieEvents();
}
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/ServiceProviders/ContactPerson.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/ServiceProviders/ContactPerson.cs
index 5da6ee4..9a65e25 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/ServiceProviders/ContactPerson.cs
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Models/ServiceProviders/ContactPerson.cs
@@ -16,13 +16,13 @@ public interface IContactPerson
ContactKind GetContactKind();
ContactTypeType ContactType { get; set; }
(bool, string) Validate();
-
Saml.SP.ContactType GetContactForXml(ServiceProvider sp);
}
public abstract class BaseContactPerson : IContactPerson
{
private string _province;
+ private string[] _nace2codes;
public string Municipality { get; set; }
public string Province { get { return Country != "IT" ? "EE" : _province; } set { _province = value; } }
@@ -31,9 +31,6 @@ public abstract class BaseContactPerson : IContactPerson
public string[] EmailAddress { get; set; }
public string[] TelephoneNumber { get; set; }
public ContactTypeType ContactType { get; set; }
-
- private string[] _nace2codes;
-
public string VATNumber { get; set; }
public string FiscalCode { get; set; }
public string[] NACE2Codes { get { return _nace2codes; } set { _nace2codes = value; } }
@@ -46,22 +43,37 @@ public bool IsItalian()
public Saml.SP.ContactType GetContactForXml(ServiceProvider sp)
{
- var elements = GetSpecificElements();
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, GetContactKind().ToString()));
+ //the code order is strange because spid-sp-test require to respect items order
+ var elements = new List();
+ var values = new List();
+ elements.Add(GetContactKind() == ContactKind.Private ? ItemsChoiceType7.Private : ItemsChoiceType7.Public);
+ values.Add(""); //Private and Public have no value
+ var (specElements, specValues) = GetSpecificElements();
+ elements.AddRange(specElements);
+ values.AddRange(specValues);
if (!string.IsNullOrWhiteSpace(VATNumber))
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, ItemsChoiceType7.VATNumber.ToString(), VATNumber));
+ {
+ elements.Add(ItemsChoiceType7.VATNumber);
+ values.Add(this.VATNumber);
+ }
if (!string.IsNullOrWhiteSpace(FiscalCode))
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, ItemsChoiceType7.FiscalCode.ToString(), FiscalCode));
+ {
+ elements.Add(ItemsChoiceType7.FiscalCode);
+ values.Add(this.FiscalCode);
+ }
if (NACE2Codes.Length > 0)
foreach (var code in NACE2Codes)
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, ItemsChoiceType7.NACE2Code.ToString(), code));
-
+ {
+ elements.Add(ItemsChoiceType7.NACE2Code);
+ values.Add(code);
+ }
var extensions = new Saml.SP.ContactPersonSPExtensionType()
{
+ Items = values.ToArray(),
+ ItemsElementName = elements.ToArray(),
Municipality = this.Municipality,
- Country = this.Country,
- Any = elements.ToArray()
+ Country = this.Country
};
if (!string.IsNullOrEmpty(this.Province))
@@ -81,11 +93,13 @@ public Saml.SP.ContactType GetContactForXml(ServiceProvider sp)
{
if (string.IsNullOrWhiteSpace(Municipality))
return (false, $"No {nameof(Municipality)} are specified");
+ if (EmailAddress.Length == 0 || EmailAddress.Length == 1 && string.IsNullOrEmpty(EmailAddress[0]))
+ return (false, $"No {nameof(EmailAddress)} are specified");
return SpecificValidate();
}
- public abstract List GetSpecificElements();
+ public abstract (List, List) GetSpecificElements();
public abstract (bool, string) SpecificValidate();
@@ -111,17 +125,15 @@ public override (bool, string) SpecificValidate()
return (true, "");
}
- public override List GetSpecificElements()
+ public override (List, List) GetSpecificElements()
{
- var elements = new List();
- return elements;
+ return (new List(), new List());
}
}
public class PublicContactPerson : BaseContactPerson
{
-
public string IPACode { get; set; }
public string IPACategory { get; set; }
@@ -138,15 +150,20 @@ public override (bool, string) SpecificValidate()
return (true, "");
}
- public override List GetSpecificElements()
+ public override (List, List) GetSpecificElements()
{
- var elements = new List();
+ var elements = new List();
+ var values = new List();
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, ItemsChoiceType7.IPACode.ToString(), IPACode));
+ elements.Add(ItemsChoiceType7.IPACode);
+ values.Add(this.IPACode);
if (!string.IsNullOrWhiteSpace(IPACategory))
- elements.Add(XmlHelpers.GetXmlElement(Saml.SamlConst.cie, Saml.SamlConst.cieNamespace, ItemsChoiceType7.IPACategory.ToString(), IPACategory));
+ {
+ elements.Add(ItemsChoiceType7.IPACategory);
+ values.Add(this.IPACategory);
+ }
- return elements;
+ return (elements, values);
}
}
}
\ No newline at end of file
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/SamlHandler.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/SamlHandler.cs
index d77c88e..03c2617 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/SamlHandler.cs
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/SamlHandler.cs
@@ -20,11 +20,10 @@ internal static class SamlHandler
{ typeof(ResponseType), new XmlSerializer(typeof(ResponseType)) },
{ typeof(LogoutRequestType), new XmlSerializer(typeof(LogoutRequestType)) },
{ typeof(LogoutResponseType), new XmlSerializer(typeof(LogoutResponseType)) },
+ { typeof(SP.EntityDescriptorType), new XmlSerializer(typeof(SP.EntityDescriptorType)) },
};
private static readonly List listAuthRefValid = new List
{
- SamlConst.SpidL + "1",
- SamlConst.SpidL + "2",
SamlConst.SpidL + "3"
};
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/cie.xsd b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/cie.xsd
index c6b8a16..cea39db 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/cie.xsd
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/cie.xsd
@@ -11,9 +11,9 @@
-
-
-
+
+
+
@@ -22,14 +22,17 @@
+
+
+
-
-
-
+
+
+
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/saml-schema-metadata-sp-cie.xsd b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/saml-schema-metadata-sp-cie.xsd
index 49e7269..a242cd3 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/saml-schema-metadata-sp-cie.xsd
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.Authentication/Saml/xsd/saml-schema-metadata-sp-cie.xsd
@@ -111,6 +111,7 @@
+
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/ServiceProvidersFactory.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/ServiceProvidersFactory.cs
new file mode 100644
index 0000000..cb68b6b
--- /dev/null
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/ServiceProvidersFactory.cs
@@ -0,0 +1,107 @@
+using Microsoft.Extensions.Options;
+using CIE.AspNetCore.Authentication.Models;
+using SPIDSS = CIE.AspNetCore.Authentication.Models.ServiceProviders;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using CIE.AspNetCore.Authentication.Models.ServiceProviders;
+
+namespace CIE.AspNetCore.WebApp
+{
+ public class ServiceProvidersFactory : IServiceProvidersFactory
+ {
+ private readonly CieOptions _options;
+
+ public ServiceProvidersFactory(IOptionsMonitor options)
+ {
+ _options = options.CurrentValue;
+ }
+
+ public Task> GetServiceProviders()
+ => Task.FromResult(new List() {
+ new ServiceProviderStandard()
+ {
+ FileName = "metadata.xml",
+ Certificate = _options.Certificate,
+ Id = Guid.NewGuid(),
+ EntityId = _options.EntityId,
+ SingleLogoutServiceLocations = new List() {
+ new SingleLogoutService() {
+ Location = "https://localhost:5001/signout-cie",
+ ProtocolBinding = ProtocolBinding.POST
+ }
+ },
+ AssertionConsumerServices = new System.Collections.Generic.List() {
+ new AssertionConsumerService(){
+ Index = 0,
+ IsDefault = true,
+ Location = "https://localhost:5001/signin-cie",
+ ProtocolBinding = ProtocolBinding.POST
+ },
+ new AssertionConsumerService() {
+ Index = 1,
+ IsDefault = false,
+ Location = "https://localhost:5001/signin-cie",
+ ProtocolBinding = ProtocolBinding.Redirect
+ }
+ },
+ AttributeConsumingServices = new System.Collections.Generic.List() {
+ new AttributeConsumingService() {
+ Index = 0,
+ ServiceDescription = "Service 1 Description",
+ ClaimTypes = new CieClaimTypes[] {
+ CieClaimTypes.Name,
+ CieClaimTypes.FamilyName,
+ CieClaimTypes.FiscalNumber,
+ CieClaimTypes.DateOfBirth
+ }
+ },
+ new AttributeConsumingService() {
+ Index = 1,
+ ServiceDescription = "Service 2 Description",
+ ClaimTypes = new CieClaimTypes[] {
+ CieClaimTypes.Name,
+ CieClaimTypes.FamilyName,
+ CieClaimTypes.FiscalNumber,
+ CieClaimTypes.DateOfBirth
+ }
+ }
+ },
+ OrganizationName = "Organizzazione fittizia per il collaudo",
+ OrganizationDisplayName = "Oganizzazione fittizia per il collaudo",
+ OrganizationURL = "https://www.asfweb.it/",
+ ContactPersons = new System.Collections.Generic.List() {
+ new PrivateContactPerson() {
+ ContactType = Authentication.Saml.SP.ContactTypeType.administrative,
+ Company = "Partner Tecnologico per Soluzioni di Identità Federata s.r.l.",
+ EmailAddress = new string[] { "info.cie@partnertecnologicoidfederata.com" },
+ TelephoneNumber = new string[] { "+390999135792" },
+ VATNumber = "IT01234567890",
+ FiscalCode = "9876543210",
+ NACE2Codes = new string[] { "CODICE_ATECO" },
+ Municipality = "CODICE_ISTAT_SEDE"
+ }/*,
+ new PublicContactPerson() {
+ ContactType = Authentication.Saml.SP.ContactTypeType.administrative,
+ EmailAddress = new string[] { "esempio_sp_privato@spp.it" },
+ TelephoneNumber = new string[] { "+39061234567" },
+ IPACode = "codiceIPA_SP",
+ IPACategory = "categoriaIPA_SP",
+ NACE2Codes = new string[] { "CODICE_ATECO" },
+ Municipality = "CODICE_ISTAT_SEDE"
+ },
+ new PrivateContactPerson() {
+ ContactType = Authentication.Saml.SP.ContactTypeType.technical,
+ Company = "Partner Tecnologico per Soluzioni di Identità Federata s.r.l.",
+ EmailAddress = new string[] { "info.cie@partnertecnologicoidfederata.com" },
+ TelephoneNumber = new string[] { "+390999135792" },
+ VATNumber = "IT01234567890",
+ FiscalCode = "9876543210",
+ NACE2Codes = new string[] { "CODICE_ATECO" },
+ Municipality = "CODICE_ISTAT_SEDE"
+ }*/
+ }
+ }
+ });
+ }
+}
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/Startup.cs b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/Startup.cs
index 956543f..7384d46 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/Startup.cs
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/Startup.cs
@@ -37,10 +37,11 @@ public void ConfigureServices(IServiceCollection services)
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = CieDefaults.AuthenticationScheme;
})
- .AddCie(Configuration, o => {
- o.Events.OnTokenCreating = async (s) => await s.HttpContext.RequestServices.GetRequiredService().TokenCreating(s);
+ .AddCie(o => {
o.LoadFromConfiguration(Configuration);
+ o.Events.OnTokenCreating = async (s) => await s.HttpContext.RequestServices.GetRequiredService().TokenCreating(s);
})
+ .AddServiceProvidersFactory()
.AddCookie();
services.AddScoped();
}
@@ -65,6 +66,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseAuthentication();
app.UseAuthorization();
+ app.AddCieSPMetadataEndpoints();
+
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
diff --git a/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/appsettings.json b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/appsettings.json
index 4e831b4..de44415 100644
--- a/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/appsettings.json
+++ b/CIE.AspNetCore.Authentication/CIE.AspNetCore.WebApp/appsettings.json
@@ -21,7 +21,7 @@
"SecurityLevel": 3
},
"Certificate": {
- "Source": "Raw",
+ "Source": "File",
"Store": {
"Location": "CurrentUser",
"Name": "My",
@@ -30,16 +30,16 @@
"validOnly": false
},
"File": {
- "Path": "xxx.pfx",
- "Password": "xxx"
+ "Path": "wwwroot/cie/ComuneVigata-SPID.pfx",
+ "Password": "P@ssW0rd!"
},
"Raw": {
- "Certificate": "test",
- "Password": "test"
+ "Certificate": "base64",
+ "Password": "password"
}
},
- "EntityId": "https://entityID",
- "AssertionConsumerServiceIndex": 2,
+ "EntityId": "https://entityID/ENTE_TEST",
+ "AssertionConsumerServiceIndex": 0,
"AttributeConsumingServiceIndex": 0
},
"AllowedHosts": "*"
diff --git a/README.md b/README.md
index c894eeb..0545082 100644
--- a/README.md
+++ b/README.md
@@ -161,8 +161,120 @@ public class CustomCieEvents : CieEvents
}
```
+# Generazione Metadata Service Provider
+La libreria è dotata della possibilità di generare dinamicamente dei metadata per Service Provider conformi ai profili privati e pubblici indicati nel **Manuale Tecnico** CIE.
+
+E' possibile aggiungere nuovi ServiceProvider sia in maniera procedurale, in fase di `Startup`, come segue:
+
+```csharp
+.AddSpid(o =>
+{
+ o.LoadFromConfiguration(Configuration);
+ o.ServiceProviders.AddRange(GetServiceProviders(o));
+})
+
+......
+
+private List GetServiceProviders(SpidOptions o)
+{
+ return new List(){
+ new ServiceProviderStandard()
+ {
+ FileName = "metadata.xml",
+ Certificate = _options.Certificate,
+ Id = Guid.NewGuid(),
+ EntityId = _options.EntityId,
+ SingleLogoutServiceLocations = new List() {
+ new SingleLogoutService() {
+ Location = "https://localhost:5001/signout-cie",
+ ProtocolBinding = ProtocolBinding.POST
+ }
+ },
+ AssertionConsumerServices = new System.Collections.Generic.List() {
+ new AssertionConsumerService(){
+ Index = 0,
+ IsDefault = true,
+ Location = "https://localhost:5001/signin-cie",
+ ProtocolBinding = ProtocolBinding.POST
+ },
+ new AssertionConsumerService() {
+ Index = 1,
+ IsDefault = false,
+ Location = "https://localhost:5001/signin-cie",
+ ProtocolBinding = ProtocolBinding.Redirect
+ }
+ },
+ AttributeConsumingServices = new System.Collections.Generic.List() {
+ new AttributeConsumingService() {
+ Index = 0,
+ ServiceDescription = "Service 1 Description",
+ ClaimTypes = new CieClaimTypes[] {
+ CieClaimTypes.Name,
+ CieClaimTypes.FamilyName,
+ CieClaimTypes.FiscalNumber,
+ CieClaimTypes.DateOfBirth
+ }
+ },
+ new AttributeConsumingService() {
+ Index = 1,
+ ServiceDescription = "Service 2 Description",
+ ClaimTypes = new CieClaimTypes[] {
+ CieClaimTypes.Name,
+ CieClaimTypes.FamilyName,
+ CieClaimTypes.FiscalNumber,
+ CieClaimTypes.DateOfBirth
+ }
+ }
+ },
+ OrganizationName = "Organizzazione fittizia per il collaudo",
+ OrganizationDisplayName = "Oganizzazione fittizia per il collaudo",
+ OrganizationURL = "https://www.asfweb.it/",
+ ContactPersons = new System.Collections.Generic.List() {
+ new PrivateContactPerson() {
+ ContactType = Authentication.Saml.SP.ContactTypeType.administrative,
+ Company = "Partner Tecnologico per Soluzioni di Identità Federata s.r.l.",
+ EmailAddress = new string[] { "info.cie@partnertecnologicoidfederata.com" },
+ TelephoneNumber = new string[] { "+390999135792" },
+ VATNumber = "IT01234567890",
+ FiscalCode = "9876543210",
+ NACE2Codes = new string[] { "CODICE_ATECO" },
+ Municipality = "CODICE_ISTAT_SEDE"
+ }
+ }
+ },
+.......
+```
+sia utilizzando una classe che implementa l'interfaccia `IServiceProvidersFactory` e configurandola come segue:
+
+```csharp
+.AddSpid(o =>
+{
+ o.LoadFromConfiguration(Configuration);
+})
+.AddServiceProvidersFactory();
+
+........
+
+public class ServiceProvidersFactory : IServiceProvidersFactory
+{
+ public Task> GetServiceProviders()
+ => Task.FromResult(new List() {
+ new Authentication.Models.ServiceProviders.ServiceProviderStandard()
+ {
+..............
+```
+
+Infine, per poter esporre gli endpoint dei metadata relativi ai Service Provider registrati, sarà necessario aggiungere la seguente riga:
+```csharp
+app.AddSpidSPMetadataEndpoints();
+```
+
+Tutti i metadata generati vengono automaticamente esposti su endpoint diversi, che hanno come BasePath `/metadata-cie` (ad esempio, un metadata definito con NomeFile = `metadata.xml` verrà esposto sull'endpoint `/metadata-cie/metadata.xml`): il BasePath può essere cambiato, sovrascrivendo la proprietà `ServiceProvidersMetadataEndpointsBasePath` sulle SpidOptions nello `Startup.cs`.
+
+All'interno dell'esempio `CIE.AspNetCore.WebApp` è presente un ServiceProvider di esempio configurato tramite `IServiceProvidersFactory`.
+
# Error Handling
-La libreria può, in qualunque fase (sia in fase di creazione della Request sia in fase di gestione della Response), sollevare eccezioni.
+La libreria può, in qualunque fase (sia in fase di creazione della Request sia in fase di gestione della Response), sollevare eccezioni.
Un tipico scenario è quello in cui vengono ricevuti i codici di errore previsti dal protocollo (n.19, n.20, ecc....), in tal caso la libreria solleva un'eccezione contenente il corrispondente messaggio d'errore localizzato, richiesto dalle specifiche CIE3.0, che è possibile gestire (ad esempio per la visualizzazione) utilizzando il normale flusso previsto per AspNetCore. L'esempio seguente fa uso del middleware di ExceptionHandling di AspNetCore.
```csharp