Suporte
Faça perguntas no Stack Overflow e marque com 'itfoxtec-identity-saml2'.
Contacte contact@foxids.com para consultoria paga.
Pacote
Lançamentos
NuGet ITfoxtec Identity SAML 2.0
NuGet ITfoxtec Identity SAML 2.0 MVC
NuGet ITfoxtec Identity SAML 2.0 MVC Core
Código e licença
Código GitHub e exemplo
Licença open source
ITfoxtec Identity SAML 2.0
O pacote open source ITfoxtec Identity Saml2 adiciona suporte SAML P tanto para Identity Provider (IdP) como para Relying Party (RP) além da funcionalidade SAML 2.0 implementada em .NET.
O nome da empresa ITfoxtec mudou para FoxIDs mas os componentes manterão o nome ITfoxtec como parte do nome do componente por agora.
- .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
O pacote ITfoxtec Identity Saml2 implementa as partes mais importantes do padrão SAML P e algumas funcionalidades opcionais. Assinatura e validação de mensagens, bem como desencriptação, são suportadas. O pacote suporta login SAML 2.0, logout, single logout e metadata. Tanto SP Initiated como IdP Initiated sign on são suportados.
O pacote ITfoxtec Identity Saml2 é testado quanto à conformidade com Microsoft Entra ID (Azure AD), AD FS, Azure AD B2C, o NemLog-in3 dinamarquês (MitID), o Context Handler dinamarquês (em dinamarquês chamado Fælleskommunal Adgangsstyring) e muitos outros IdPs e RPs.
Consulte os exemplos de teste.
Contacte Anders Revsgaard (anders@foxids.com) se precisar de um exemplo para um IdP específico como o NemLog-in (MitID) dinamarquês ou o Context Handler.
É um serviço pago onde pode adquirir um pacote de exemplo pronto a usar para um IdP ou solicitar um exemplo personalizado.
>
Pode usar a ferramenta SAML 2.0 para descodificar tokens e criar certificados auto assinados com a ferramenta de certificados.
Bindings suportados:
- Binding Redirect
- Binding Post
- Binding Artifact
Os bindings podem ser usados conforme necessário para:
- Authn Request
- Authn Response (SAML 2.0 Response)
- Logout Request
- Logout Response
SHA1/SHA256/SHA384/SHA512 é suportado para assinatura de mensagens.
- 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 e ASP.NET MVC Core são suportados pelos pacotes ITfoxtec Identity SAML 2.0 MVC e MVC Core, que ajudam a integrar o pacote ITfoxtec SAML 2.0 numa aplicação MVC ou MVC Core.
Código
O código apresentado é apenas uma seleção do código de exemplo no GitHub.
O pacote ITfoxtec Identity Saml2 é integrado numa aplicação ASP.NET MVC Core Relying Party (RP) através da configuração no Startup e adicionando um Auth Controller com os quatro métodos seguintes. O binding apresentado pode ser alterado conforme necessário dependendo dos requisitos.
É ainda possível definir alguns parâmetros opcionais no Saml2AuthnRequest e no Saml2LogoutRequest. No Saml2AuthnRequest, por exemplo, o ForceAuthn é suportado, o que irá forçar o utilizador a introduzir credenciais mesmo que já exista um contexto SSO no Security Token Service (STS) / Identity Provider (IdP).
Adicionar configuração ao método ConfigureServices no Startup
Configuração usando metadados do 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();
Configuração sem metadados.
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 Login no 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 no Auth Controller
Após um login bem-sucedido ou falhado, o método ACS recebe a resposta.[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 Logout no 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 no Auth Controller
Após um logout bem-sucedido ou falhado, o método LoggedOut recebe a resposta.[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 no Auth Controller
Recebe um pedido Single Logout e envia uma resposta.[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(); }