Soporte

Haz preguntas en Stack Overflow y etiqueta con « itfoxtec-identity-saml2 ».

Contacta contact@foxids.com para consultoría de pago.

Paquete

Versiones
NuGet ITfoxtec Identity SAML 2.0
NuGet ITfoxtec Identity SAML 2.0 MVC
NuGet ITfoxtec Identity SAML 2.0 MVC Core

Código y licencia

Código y ejemplo en GitHub
Licencia de código abierto

ITfoxtec Identity SAML 2.0

El paquete de código abierto ITfoxtec Identity Saml2 añade soporte SAML-P tanto para Identity Provider (IdP) como para Relying Party (RP) además de la funcionalidad SAML 2.0 implementada en .NET.

El nombre de la empresa ITfoxtec ha cambiado a FoxIDs pero los componentes mantendrán el nombre ITfoxtec como parte del nombre del componente por ahora.

Versiones .NET compatibles:
  • .NET 10.0
  • .NET 9.0
  • .NET 8.0
  • .NET 7.0
  • .NET 6.0
  • .NET Standard 2.1
  • .NET Framework 4.6.2 and 4.8

El paquete ITfoxtec Identity Saml2 implementa las partes más importantes del estándar SAML-P y algunas funciones opcionales. Se admite la firma y validación de mensajes, así como el descifrado. El paquete soporta inicio de sesión, cierre de sesión, single logout y metadatos SAML 2.0. Se admiten inicios de sesión SP Initiated e IdP Initiated.

El paquete ITfoxtec Identity Saml2 está probado para cumplir con Microsoft Entra ID (Azure AD), AD FS, Azure AD B2C, el NemLog-in3 danés (MitID), el Context Handler danés (en danés Fælleskommunal Adgangsstyring) y muchos otros IdP y RP.

Consulta los ejemplos de prueba.

Contacta Anders Revsgaard (anders@foxids.com) si necesitas un ejemplo para un IdP específico como el NemLog-in (MitID) danés o Context Handler.
Es un servicio de pago donde puedes comprar un paquete de ejemplo listo para usar para un IdP o solicitar un ejemplo personalizado.

Puedes usar la herramienta SAML 2.0 para decodificar tokens y crear certificados autofirmados con la herramienta de certificados.

Bindings compatibles:

  • Redirect Binding
  • Post Binding
  • Artifact Binding

Los bindings se pueden usar según sea necesario para:

  • Authn Request
  • Authn Response (SAML 2.0 Response)
  • Logout Request
  • Logout Response

Se admite SHA1/SHA256/SHA384/SHA512 para la firma de mensajes.

  • SHA1: http://www.w3.org/2000/09/xmldsig#rsa-sha1
  • SHA256: http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
  • SHA384: http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
  • SHA512: http://www.w3.org/2001/04/xmldsig-more#rsa-sha512

ASP.NET MVC y ASP.NET MVC Core son compatibles con los paquetes ITfoxtec Identity SAML 2.0 MVC y MVC Core, que ayudan a integrar el paquete ITfoxtec SAML 2.0 en una aplicación MVC o MVC Core.

Código

El código mostrado es solo una selección del código de ejemplo en GitHub.

El paquete ITfoxtec Identity Saml2 se integra en una aplicación ASP.NET MVC Core Relying Party (RP) mediante configuración en Startup y añadiendo un Auth Controller con los siguientes cuatro métodos. El binding mostrado puede cambiarse según los requisitos.

Además, es posible establecer algunos parámetros opcionales en Saml2AuthnRequest y Saml2LogoutRequest. En Saml2AuthnRequest, por ejemplo, se admite ForceAuthn, que obliga al usuario a ingresar credenciales incluso si ya existe un contexto SSO en el Security Token Service (STS) / Identity Provider (IdP).


Agregar configuración al método ConfigureServices en Startup

Configuración usando metadatos del IdP.
services.Configure<Saml2Configuration>(Configuration.GetSection("Saml2"));
services.Configure<Saml2Configuration>(saml2Configuration =>
{
    saml2Configuration.SigningCertificate = CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
        Configuration["Saml2:SigningCertificateFile"]), Configuration["Saml2:SigningCertificatePassword"]);
    saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);

    var entityDescriptor = new EntityDescriptor();
    entityDescriptor.ReadIdPSsoDescriptorFromUrl(new Uri(Configuration["Saml2:IdPMetadata"]));
    if (entityDescriptor.IdPSsoDescriptor != null)
    {
        saml2Configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
        saml2Configuration.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
        saml2Configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
    }
    else
    {
        throw new Exception("IdPSsoDescriptor not loaded from metadata.");
    }
});
services.AddSaml2();   

Configuración sin metadatos.
services.Configure<Saml2Configuration>(Configuration.GetSection("Saml2"));
services.Configure<Saml2Configuration>(saml2Configuration =>
{
    saml2Configuration.SigningCertificate = CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
        Configuration["Saml2:SigningCertificateFile"]), Configuration["Saml2:SigningCertificatePassword"]);
    saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);

    saml2Configuration.SignatureValidationCertificates.Add(CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
        Configuration["Saml2:SignatureValidationCertificateFile"])));
});
services.AddSaml2();   

Método de login en el Auth Controller

[Route("Login")]
public IActionResult Login(string returnUrl = null)
{
    var binding = new Saml2RedirectBinding();
    binding.SetRelayStateQuery(new Dictionary<string, string> 
        { { relayStateReturnUrl, returnUrl ?? Url.Content("~/") } });

    return binding.Bind(new Saml2AuthnRequest(config)).ToActionResult();
}

Método AssertionConsumerService en el Auth Controller

Después de un login exitoso o fallido, el método ACS recibe la respuesta.
[Route("AssertionConsumerService")]
public async Task<IActionResult> AssertionConsumerService()
{       
    var httpRequest = Request.ToGenericHttpRequest(validate: true);
    var saml2AuthnResponse = new Saml2AuthnResponse(config);

    httpRequest.Binding.Unbind(httpRequest, saml2AuthnResponse);
    await saml2AuthnResponse.CreateSession(HttpContext, 
        ClaimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));

    var returnUrl = httpRequest.Binding.GetRelayStateQuery()[relayStateReturnUrl];
    return Redirect(string.IsNullOrWhiteSpace(returnUrl) ? Url.Content("~/") : returnUrl);
}

Método de logout en el Auth Controller

[HttpPost("Logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
    if (!User.Identity.IsAuthenticated)
    {
        return Redirect(Url.Content("~/"));
    }

    var binding = new Saml2PostBinding();
    var saml2LogoutRequest = await new Saml2LogoutRequest(config, User).DeleteSession(HttpContext);
    return binding.Bind(saml2LogoutRequest).ToActionResult();
}

Método LoggedOut en el Auth Controller

Después de un logout exitoso o fallido, el método LoggedOut recibe la respuesta.
[Route("LoggedOut")]
public IActionResult LoggedOut()
{
    var httpRequest = Request.ToGenericHttpRequest(validate: true);
    httpRequest.Binding.Unbind(httpRequest, new Saml2LogoutResponse(config));

    return Redirect(Url.Content("~/"));
}

Método SingleLogout en el Auth Controller

Recibe una solicitud Single Logout y envía una respuesta.
[Route("SingleLogout")]
public async Task<IActionResult> SingleLogout()
{
    Saml2StatusCodes status;
    var httpRequest = Request.ToGenericHttpRequest(validate: true);
    var logoutRequest = new Saml2LogoutRequest(config, User);
    try
    {
        httpRequest.Binding.Unbind(httpRequest, logoutRequest);
        status = Saml2StatusCodes.Success;
        await logoutRequest.DeleteSession(HttpContext);
    }
    catch (Exception exc)
    {
        // log exception
        Debug.WriteLine("SingleLogout error: " + exc.ToString());
        status = Saml2StatusCodes.RequestDenied;
    }

    var responseBinding = new Saml2PostBinding();
    responseBinding.RelayState = httpRequest.Binding.RelayState;
    var saml2LogoutResponse = new Saml2LogoutResponse(config)
    {
        InResponseToAsString = logoutRequest.IdAsString,
        Status = status,
    };
    return responseBinding.Bind(saml2LogoutResponse).ToActionResult();
}

Tu privacidad

Usamos cookies para mejorar tu experiencia en nuestros sitios web. Haz clic en «Aceptar todas las cookies» para aceptar su uso. Para rechazar cookies no esenciales, haz clic en «Solo cookies necesarias».

Visita nuestra política de privacidad para saber más