private async Task <IActionResult> SingleLogoutRequestAsync <T>(SamlDownParty party, Saml2Binding <T> binding, IEnumerable <Claim> claims) { var samlConfig = saml2ConfigurationLogic.GetSamlDownConfig(party, true); claims = await claimTransformationsLogic.Transform(party.ClaimTransforms?.ConvertAll(t => (ClaimTransform)t), claims); var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig) { NameId = samlClaimsDownLogic.GetNameId(claims), Destination = new Uri(party.SingleLogoutUrl), SessionIndex = samlClaimsDownLogic.GetSessionIndex(claims) }; binding.RelayState = SequenceString; binding.Bind(saml2LogoutRequest); logger.ScopeTrace($"SAML Single Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'."); logger.ScopeTrace($"Single logged out URL '{party.SingleLogoutUrl}'."); logger.ScopeTrace("Down, SAML Single Logout request.", triggerEvent: true); securityHeaderLogic.AddFormAction(party.SingleLogoutUrl); if (binding is Saml2Binding <Saml2RedirectBinding> ) { return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync()); } if (binding is Saml2Binding <Saml2PostBinding> ) { return(await(binding as Saml2PostBinding).ToActionFormResultAsync()); } else { throw new NotSupportedException(); } }
private async Task <IActionResult> SingleLogoutResponseAsync <T>(SamlDownParty party, Saml2Binding <T> binding) { var samlConfig = await saml2ConfigurationLogic.GetSamlDownConfigAsync(party); var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig); binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse); logger.ScopeTrace(() => $"SAML Single Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message); ValidateLogoutResponse(party, saml2LogoutResponse); await sequenceLogic.ValidateExternalSequenceIdAsync(binding.RelayState); try { binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse); logger.ScopeTrace(() => "Down, SAML Single Logout response accepted.", triggerEvent: true); } catch (Exception ex) { var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex); if (isex != null) { throw isex; } throw; } return(await singleLogoutDownLogic.HandleSingleLogoutAsync()); }
private LoginRequest GetLoginRequestAsync(SamlDownParty party, Saml2AuthnRequest saml2AuthnRequest) { var loginRequest = new LoginRequest { DownPartyLink = new DownPartySessionLink { SupportSingleLogout = !string.IsNullOrWhiteSpace(party.SingleLogoutUrl), Id = party.Id, Type = party.Type } }; if (saml2AuthnRequest.ForceAuthn.HasValue && saml2AuthnRequest.ForceAuthn.Value) { loginRequest.LoginAction = LoginAction.RequireLogin; } else if (saml2AuthnRequest.IsPassive.HasValue && saml2AuthnRequest.IsPassive.Value) { loginRequest.LoginAction = LoginAction.ReadSession; } else { loginRequest.LoginAction = LoginAction.ReadSessionOrLogin; } if (saml2AuthnRequest.RequestedAuthnContext?.AuthnContextClassRef?.Count() > 0) { loginRequest.Acr = saml2AuthnRequest.RequestedAuthnContext?.AuthnContextClassRef; } return(loginRequest); }
public Saml2Configuration GetSamlDownConfig(SamlDownParty party, bool includeSigningCertificate = false) { var samlConfig = new Saml2Configuration(); samlConfig.Issuer = !party.IdPIssuer.IsNullOrEmpty() ? party.IdPIssuer : trackIssuerLogic.GetIssuer(); if (party.Keys?.Count > 0) { foreach (var key in party.Keys) { samlConfig.SignatureValidationCertificates.Add(key.ToSaml2X509Certificate()); } } if (includeSigningCertificate) { samlConfig.SigningCertificate = trackKeyLogic.GetPrimarySaml2X509Certificate(RouteBinding.Key); } samlConfig.SignatureAlgorithm = party.SignatureAlgorithm; samlConfig.CertificateValidationMode = party.CertificateValidationMode; samlConfig.RevocationMode = party.RevocationMode; return(samlConfig); }
private async Task <IActionResult> LogoutRequestAsync <T>(SamlDownParty party, Saml2Binding <T> binding) { var samlConfig = await saml2ConfigurationLogic.GetSamlDownConfigAsync(party); var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig); binding.ReadSamlRequest(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest); logger.ScopeTrace(() => $"SAML Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message); try { ValidateLogoutRequest(party, saml2LogoutRequest); try { binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest); logger.ScopeTrace(() => "Down, SAML Logout request accepted.", triggerEvent: true); } catch (Exception ex) { var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex); if (isex != null) { throw isex; } throw; } await sequenceLogic.SaveSequenceDataAsync(new SamlDownSequenceData { Id = saml2LogoutRequest.Id.Value, RelayState = binding.RelayState }); var type = RouteBinding.ToUpParties.First().Type; logger.ScopeTrace(() => $"Request, Up type '{type}'."); switch (type) { case PartyTypes.Login: return(await serviceProvider.GetService <LogoutUpLogic>().LogoutRedirect(RouteBinding.ToUpParties.First(), GetLogoutRequest(party, saml2LogoutRequest))); case PartyTypes.OAuth2: throw new NotImplementedException(); case PartyTypes.Oidc: return(await serviceProvider.GetService <OidcRpInitiatedLogoutUpLogic <OidcUpParty, OidcUpClient> >().EndSessionRequestRedirectAsync(RouteBinding.ToUpParties.First(), GetLogoutRequest(party, saml2LogoutRequest))); case PartyTypes.Saml2: return(await serviceProvider.GetService <SamlLogoutUpLogic>().LogoutRequestRedirectAsync(RouteBinding.ToUpParties.First(), GetSamlLogoutRequest(party, saml2LogoutRequest))); default: throw new NotSupportedException($"Party type '{type}' not supported."); } } catch (SamlRequestException ex) { logger.Error(ex); return(await LogoutResponseAsync(party, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState, ex.Status)); } }
public Saml2Configuration GetSamlDownConfig(SamlDownParty party, bool includeSigningCertificate = false) { var samlConfig = new Saml2Configuration(); if (!party.IdSIssuer.IsNullOrEmpty()) { samlConfig.Issuer = party.IdSIssuer; } else { samlConfig.Issuer = UrlCombine.Combine(HttpContext.GetHost(), RouteBinding.TenantName, RouteBinding.TrackName); } if (party.Keys?.Count > 0) { foreach (var key in party.Keys) { samlConfig.SignatureValidationCertificates.Add(key.ToSaml2X509Certificate()); } } if (includeSigningCertificate) { samlConfig.SigningCertificate = trackKeyLogic.GetSaml2X509Certificate(RouteBinding.PrimaryKey); } samlConfig.SignatureAlgorithm = party.SignatureAlgorithm; samlConfig.CertificateValidationMode = party.CertificateValidationMode; samlConfig.RevocationMode = party.RevocationMode; return(samlConfig); }
private bool ValidatePartySingleLogoutSupport(SamlDownParty party) { if (party.LogoutBinding == null || party.SingleLogoutUrl.IsNullOrEmpty() || party.Keys?.Count <= 0) { return(false); } return(true); }
private async Task <IActionResult> LogoutRequestAsync <T>(SamlDownParty party, Saml2Binding <T> binding) { var samlConfig = saml2ConfigurationLogic.GetSamlDownConfig(party); var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig); binding.ReadSamlRequest(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest); logger.ScopeTrace($"SAML Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'."); try { ValidateLogoutRequest(party, saml2LogoutRequest); binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest); logger.ScopeTrace("Down, SAML Logout request accepted.", triggerEvent: true); await sequenceLogic.SaveSequenceDataAsync(new SamlDownSequenceData { Id = saml2LogoutRequest.Id.Value, RelayState = binding.RelayState, ResponseUrl = party.LoggedOutUrl, }); await formActionLogic.CreateFormActionByUrlAsync(party.LoggedOutUrl); var type = RouteBinding.ToUpParties.First().Type; logger.ScopeTrace($"Request, Up type '{type}'."); switch (type) { case PartyTypes.Login: return(await serviceProvider.GetService <LogoutUpLogic>().LogoutRedirect(RouteBinding.ToUpParties.First(), new LogoutRequest { DownParty = party, SessionId = saml2LogoutRequest.SessionIndex, RequireLogoutConsent = false, PostLogoutRedirect = true, })); case PartyTypes.OAuth2: throw new NotImplementedException(); case PartyTypes.Oidc: throw new NotImplementedException(); case PartyTypes.Saml2: return(await serviceProvider.GetService <SamlLogoutUpLogic>().LogoutAsync(RouteBinding.ToUpParties.First(), GetSamlUpLogoutRequest(saml2LogoutRequest, party))); default: throw new NotSupportedException($"Party type '{type}' not supported."); } } catch (SamlRequestException ex) { logger.Error(ex); return(await LogoutResponseAsync(party.Id, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState, saml2LogoutRequest.Destination?.OriginalString, party.AuthnBinding.ResponseBinding, ex.Status)); } }
private void ValidatePartyLogoutSupport(SamlDownParty party) { if (party.LogoutBinding == null || party.LoggedOutUrl.IsNullOrEmpty() || party.Keys?.Count <= 0) { throw new EndpointException("Logout not configured.") { RouteBinding = RouteBinding }; } }
private string GetAcsUrl(SamlDownParty party, Saml2AuthnRequest saml2AuthnRequest) { if (saml2AuthnRequest.AssertionConsumerServiceUrl != null) { return(saml2AuthnRequest.AssertionConsumerServiceUrl.OriginalString); } else { return(party.AcsUrls.First()); } }
public IEnumerable <Claim> GetSubjectClaims(SamlDownParty party, IEnumerable <Claim> claims) { var acceptAllClaims = party.Claims?.Where(c => c == "*")?.Count() > 0; if (!acceptAllClaims) { var acceptedClaims = Constants.DefaultClaims.SamlClaims.ConcatOnce(party.Claims); claims = claims.Where(c => acceptedClaims.Any(ic => ic == c.Type)); } return(claims); }
private LogoutRequest GetLogoutRequest(SamlDownParty party, Saml2LogoutRequest saml2LogoutRequest) { return(new LogoutRequest { DownPartyLink = new DownPartySessionLink { SupportSingleLogout = !string.IsNullOrWhiteSpace(party.SingleLogoutUrl), Id = party.Id, Type = party.Type }, SessionId = saml2LogoutRequest.SessionIndex, RequireLogoutConsent = false, PostLogoutRedirect = true, }); }
private async Task <IActionResult> AuthnRequestAsync <T>(SamlDownParty party, Saml2Binding <T> binding) { var samlConfig = saml2ConfigurationLogic.GetSamlDownConfig(party); var request = HttpContext.Request; var saml2AuthnRequest = new Saml2AuthnRequest(samlConfig); binding.ReadSamlRequest(request.ToGenericHttpRequest(), saml2AuthnRequest); logger.ScopeTrace($"SAML Authn request '{saml2AuthnRequest.XmlDocument.OuterXml}'."); try { ValidateAuthnRequest(party, saml2AuthnRequest); binding.Unbind(request.ToGenericHttpRequest(), saml2AuthnRequest); logger.ScopeTrace("Down, SAML Auth request accepted.", triggerEvent: true); var responseUrl = GetAcsUrl(party, saml2AuthnRequest); await sequenceLogic.SaveSequenceDataAsync(new SamlDownSequenceData { Id = saml2AuthnRequest.Id.Value, RelayState = binding.RelayState, ResponseUrl = responseUrl, }); await formActionLogic.CreateFormActionByUrlAsync(responseUrl); var type = RouteBinding.ToUpParties.First().Type; logger.ScopeTrace($"Request, Up type '{type}'."); switch (type) { case PartyTypes.Login: return(await serviceProvider.GetService <LoginUpLogic>().LoginRedirectAsync(RouteBinding.ToUpParties.First(), GetLoginRequestAsync(party, saml2AuthnRequest))); case PartyTypes.OAuth2: throw new NotImplementedException(); case PartyTypes.Oidc: return(await serviceProvider.GetService <OidcAuthUpLogic <OidcDownParty, OidcDownClient, OidcDownScope, OidcDownClaim> >().AuthenticationRequestAsync(RouteBinding.ToUpParties.First())); case PartyTypes.Saml2: return(await serviceProvider.GetService <SamlAuthnUpLogic>().AuthnRequestAsync(RouteBinding.ToUpParties.First(), GetLoginRequestAsync(party, saml2AuthnRequest))); default: throw new NotSupportedException($"Party type '{type}' not supported."); } } catch (SamlRequestException ex) { logger.Error(ex); return(await AuthnResponseAsync(party.Id, samlConfig, saml2AuthnRequest.Id.Value, binding.RelayState, GetAcsUrl(party, saml2AuthnRequest), party.AuthnBinding.ResponseBinding, ex.Status)); } }
private async Task <IActionResult> AuthnResponseAsync <T>(SamlDownParty party, Saml2Configuration samlConfig, string inResponseTo, string relayState, string acsUrl, Saml2Binding <T> binding, Saml2StatusCodes status, IEnumerable <Claim> claims) { binding.RelayState = relayState; var saml2AuthnResponse = new FoxIDsSaml2AuthnResponse(settings, samlConfig) { InResponseTo = new Saml2Id(inResponseTo), Status = status, Destination = new Uri(acsUrl), }; if (status == Saml2StatusCodes.Success && party != null && claims != null) { claims = await claimTransformationsLogic.Transform(party.ClaimTransforms?.ConvertAll(t => (ClaimTransform)t), claims); saml2AuthnResponse.SessionIndex = samlClaimsDownLogic.GetSessionIndex(claims); saml2AuthnResponse.NameId = samlClaimsDownLogic.GetNameId(claims); var tokenIssueTime = DateTimeOffset.UtcNow; var tokenDescriptor = saml2AuthnResponse.CreateTokenDescriptor(samlClaimsDownLogic.GetSubjectClaims(party, claims), party.Issuer, tokenIssueTime, party.IssuedTokenLifetime); var authnContext = claims.FindFirstValue(c => c.Type == ClaimTypes.AuthenticationMethod); var authenticationInstant = claims.FindFirstValue(c => c.Type == ClaimTypes.AuthenticationInstant); var authenticationStatement = saml2AuthnResponse.CreateAuthenticationStatement(authnContext, DateTime.Parse(authenticationInstant)); var subjectConfirmation = saml2AuthnResponse.CreateSubjectConfirmation(tokenIssueTime, party.SubjectConfirmationLifetime); await saml2AuthnResponse.CreateSecurityTokenAsync(tokenDescriptor, authenticationStatement, subjectConfirmation); } binding.Bind(saml2AuthnResponse); logger.ScopeTrace($"SAML Authn response '{saml2AuthnResponse.XmlDocument.OuterXml}'."); logger.ScopeTrace($"Acs URL '{acsUrl}'."); logger.ScopeTrace("Down, SAML Authn response.", triggerEvent: true); await sequenceLogic.RemoveSequenceDataAsync <SamlDownSequenceData>(); securityHeaderLogic.AddFormAction(acsUrl); if (binding is Saml2Binding <Saml2RedirectBinding> ) { return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync()); } else if (binding is Saml2Binding <Saml2PostBinding> ) { return(await(binding as Saml2PostBinding).ToActionFormResultAsync()); } else { throw new NotSupportedException(); } }
private async Task CreateAspNetCoreSamlSampleDownPartyAsync() { Func <string, Task> getAction = async(name) => { _ = await foxIDsApiClient.GetSamlDownPartyAsync(name); }; Func <string, Task> postAction = async(name) => { var baseUrl = "https://localhost:44343"; var samlUpParty = new SamlDownParty { Name = name, Issuer = "urn:itfoxtec:idservice:samples:aspnetcoresamlsample", AllowUpPartyNames = new[] { loginName, aspNetCoreSamlIdPSampleUpPartyName, identityserverOidcOpUpPartyName /*, "foxids_oidcpkce", "adfs_saml_idp"*/ }, Keys = new[] { new JsonWebKey { Kty = "RSA", Kid = "3863A8A752E5D6B812AA8A78A656E2DE6C637D12", X5c = new[] { "MIICzzCCAbegAwIBAgIJAOd44ujQLBp/MA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNVBAMTDnRlc3Qtc2lnbi1jZXJ0MB4XDTE4MTAwOTA4NTMxOFoXDTE5MTAxMDA4NTMxOFowGTEXMBUGA1UEAxMOdGVzdC1zaWduLWNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCbttrAY2VkISBs/dQW9B38dvO1++Pcqqlj0darBfq8+1f+nRsn0OcQOYAhMvPhuS7qy5NLaTFm8RbH3veybYm7cJFU6xGu8SiLv6rPa5CBrSTgL/sJ+NwIDG3ZaZbayKTqgf31D1Gv8mIOWtEVHOn9ZPvfO6r0I9tLMZtJASHDTxe7niskT2PEfGe1KBTXVgJqY67KttzlydvH4zN+lwXFguBKLQqicw9iJ9BngxDAMLkOz6SIeF5WFGRPfiLD/MOZQ/skb+1H9Bl+5mbL/F0TiVs1HaQNEt3N9SO18dRyA2ZGtGfTzJbx3gQ7RwRjmNMnK8In9M0jxZZ1Rvji2XFAgMBAAGjGjAYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQC5RtTJV7mONXWKFkmF8EnCfPbFemCZs7Usw4cicjWlPTPfneFTsSJ4NuFmpWYrf1Lr75cf9BjHZDVHDGrRTsou/wAuqSehRPlZyj35ysjrC1hNmFYKQU+WkulxE4BZIcD+3fKj+6WAPVGG0NMnKWrmie2XK0aM5nFrWST4xqk6V5+4DOT7lltmPs9eUDJ8wkIL1oP/mhsE7tKpqMk9qNCb5nZMwXhqoTnlqTw/DFDCPJV/CS20/PamGTVUUhW1I0r73QDv054ycFY0ijU3tUK2V4D3daFTBHVGlLsCUxSBJSWkTGieN+iyU5aNbCErBc0+cim79lXT6sZ8VPVJ+kdW" }, X5t = "OGOop1Ll1rgSqop4plbi3mxjfRI", N = "wm7bawGNlZCEgbP3UFvQd_Hbztfvj3KqpY9HWqwX6vPtX_p0bJ9DnEDmAITLz4bku6suTS2kxZvEWx973sm2Ju3CRVOsRrvEoi7-qz2uQga0k4C_7CfjcCAxt2WmW2sik6oH99Q9Rr_JiDlrRFRzp_WT73zuq9CPbSzGbSQEhw08Xu54rJE9jxHxntSgU11YCamOuyrbc5cnbx-MzfpcFxYLgSi0KonMPYifQZ4MQwDC5Ds-kiHheVhRkT34iw_zDmUP7JG_tR_QZfuZmy_xdE4lbNR2kDRLdzfUjtfHUcgNmRrRn08yW8d4EO0cEY5jTJyvCJ_TNI8WWdUb44tlxQ", E = "AQAB" } }, SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", CertificateValidationMode = X509CertificateValidationMode.None, RevocationMode = X509RevocationMode.NoCheck, AuthnBinding = new SamlBinding { RequestBinding = SamlBindingTypes.Redirect, ResponseBinding = SamlBindingTypes.Post }, AcsUrls = new[] { UrlCombine.Combine(baseUrl, "saml/assertionconsumerservice") }, LogoutBinding = new SamlBinding { RequestBinding = SamlBindingTypes.Post, ResponseBinding = SamlBindingTypes.Post }, SingleLogoutUrl = UrlCombine.Combine(baseUrl, "saml/singlelogout"), LoggedOutUrl = UrlCombine.Combine(baseUrl, "saml/loggedout"), Claims = new string[] { ClaimTypes.Email, ClaimTypes.Name, ClaimTypes.GivenName, ClaimTypes.Surname, ClaimTypes.Role }, MetadataLifetime = 1728000, // 20 days SubjectConfirmationLifetime = 300, // 5 minutes IssuedTokenLifetime = 36000 // 10 hours }; await foxIDsApiClient.PostSamlDownPartyAsync(samlUpParty); }; await CreateIfNotExistsAsync(aspNetCoreSamlSampleDownPartyName, getAction, postAction); }
private void ValidateLogoutRequest(SamlDownParty party, Saml2LogoutRequest saml2LogoutRequest) { var requestIssuer = saml2LogoutRequest.Issuer; logger.SetScopeProperty("Issuer", requestIssuer); if (!party.Issuer.Equals(requestIssuer)) { throw new SamlRequestException($"Invalid issuer '{requestIssuer}'.") { RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder }; } }
private async Task <IActionResult> SingleLogoutResponseAsync <T>(SamlDownParty party, Saml2Binding <T> binding) { var samlConfig = saml2ConfigurationLogic.GetSamlDownConfig(party); var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig); binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse); logger.ScopeTrace($"SAML Single Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'."); ValidateLogoutResponse(party, saml2LogoutResponse); await sequenceLogic.ValidateSequenceAsync(binding.RelayState); binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse); logger.ScopeTrace("Down, SAML Single Logout response accepted.", triggerEvent: true); return(await singleLogoutDownLogic.HandleSingleLogoutAsync()); }
private Task <IActionResult> AuthnResponseAsync(SamlDownParty party, Saml2Configuration samlConfig, string inResponseTo, string relayState, string acsUrl, Saml2StatusCodes status, IEnumerable <Claim> claims = null) { logger.ScopeTrace(() => $"Down, SAML Authn response{(status != Saml2StatusCodes.Success ? " error" : string.Empty)}, Status code '{status}'."); var binding = party.AuthnBinding.ResponseBinding; logger.ScopeTrace(() => $"Binding '{binding}'"); switch (binding) { case SamlBindingTypes.Redirect: return(AuthnResponseAsync(party, samlConfig, inResponseTo, relayState, acsUrl, new Saml2RedirectBinding(), status, claims)); case SamlBindingTypes.Post: return(AuthnResponseAsync(party, samlConfig, inResponseTo, relayState, acsUrl, new Saml2PostBinding(), status, claims)); default: throw new NotSupportedException($"SAML binding '{binding}' not supported."); } }
private Task <IActionResult> LogoutResponseAsync(SamlDownParty party, Saml2Configuration samlConfig, string inResponseTo, string relayState, Saml2StatusCodes status, string sessionIndex = null) { logger.ScopeTrace($"Down, SAML Logout response{(status != Saml2StatusCodes.Success ? " error" : string.Empty)}, Status code '{status}'."); var binding = party.LogoutBinding.ResponseBinding; logger.ScopeTrace($"Binding '{binding}'"); switch (binding) { case SamlBindingTypes.Redirect: return(LogoutResponseAsync(samlConfig, inResponseTo, relayState, party.LoggedOutUrl, new Saml2RedirectBinding(), status, sessionIndex)); case SamlBindingTypes.Post: return(LogoutResponseAsync(samlConfig, inResponseTo, relayState, party.LoggedOutUrl, new Saml2PostBinding(), status, sessionIndex)); default: throw new NotSupportedException($"SAML binding '{binding}' not supported."); } }
private LoginRequest GetLoginRequestAsync(SamlDownParty party, Saml2AuthnRequest saml2AuthnRequest) { var loginRequest = new LoginRequest { DownParty = party }; if (saml2AuthnRequest.ForceAuthn.HasValue && saml2AuthnRequest.ForceAuthn.Value) { loginRequest.LoginAction = LoginAction.RequereLogin; } else if (saml2AuthnRequest.IsPassive.HasValue && saml2AuthnRequest.IsPassive.Value) { loginRequest.LoginAction = LoginAction.ReadSession; } else { loginRequest.LoginAction = LoginAction.ReadSessionOrLogin; } return(loginRequest); }
private async Task <IActionResult> LogoutResponseAsync <T>(SamlDownParty party, Saml2Configuration samlConfig, string inResponseTo, string relayState, Saml2Binding <T> binding, Saml2StatusCodes status, string sessionIndex) { binding.RelayState = relayState; var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig) { InResponseTo = new Saml2Id(inResponseTo), Status = status, Destination = new Uri(party.LoggedOutUrl), SessionIndex = sessionIndex }; binding.Bind(saml2LogoutResponse); logger.ScopeTrace(() => $"SAML Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message); logger.ScopeTrace(() => $"Logged out URL '{party.LoggedOutUrl}'."); logger.ScopeTrace(() => "Down, SAML Logout response.", triggerEvent: true); await sequenceLogic.RemoveSequenceDataAsync <SamlDownSequenceData>(); if (party.RestrictFormAction) { securityHeaderLogic.AddFormAction(party.LoggedOutUrl); } else { securityHeaderLogic.AddFormActionAllowAll(); } if (binding is Saml2Binding <Saml2RedirectBinding> ) { return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync()); } if (binding is Saml2Binding <Saml2PostBinding> ) { return(await(binding as Saml2PostBinding).ToActionFormResultAsync()); } else { throw new NotSupportedException(); } }
private void ValidateAuthnRequest(SamlDownParty party, Saml2AuthnRequest saml2AuthnRequest) { if (saml2AuthnRequest.AssertionConsumerServiceUrl != null && !party.AcsUrls.Any(u => u.Equals(saml2AuthnRequest.AssertionConsumerServiceUrl.OriginalString, StringComparison.InvariantCultureIgnoreCase))) { throw new EndpointException($"Invalid assertion consumer service url '{saml2AuthnRequest.AssertionConsumerServiceUrl.OriginalString}'.") { RouteBinding = RouteBinding }; } var requestIssuer = saml2AuthnRequest.Issuer; logger.SetScopeProperty("Issuer", requestIssuer); if (!party.Issuer.Equals(requestIssuer)) { throw new SamlRequestException($"Invalid issuer '{requestIssuer}'.") { RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder }; } }
public async Task <FoxIDsSaml2Configuration> GetSamlDownConfigAsync(SamlDownParty party, bool includeSigningCertificate = false, bool includeSignatureValidationCertificates = true) { var samlConfig = new FoxIDsSaml2Configuration(); samlConfig.Issuer = !string.IsNullOrEmpty(party?.IdPIssuer) ? party.IdPIssuer : trackIssuerLogic.GetIssuer(); if (party != null) { if (party.Keys?.Count > 0 && includeSignatureValidationCertificates) { var partyCertificates = party.Keys.ToSaml2X509Certificates(); foreach (var partyCertificate in partyCertificates) { if (partyCertificate.IsValidLocalTime()) { samlConfig.SignatureValidationCertificates.Add(partyCertificate); } else { samlConfig.InvalidSignatureValidationCertificates.Add(partyCertificate); } } } } if (includeSigningCertificate) { samlConfig.SigningCertificate = await trackKeyLogic.GetPrimarySaml2X509CertificateAsync(RouteBinding.Key); } if (party != null) { samlConfig.SignatureAlgorithm = party.SignatureAlgorithm; samlConfig.CertificateValidationMode = party.CertificateValidationMode; samlConfig.RevocationMode = party.RevocationMode; } return(samlConfig); }
private async Task CreateAspNetCoreSamlSampleDownPartyAsync() { Func <string, Task> getAction = async(name) => { _ = await foxIDsApiClient.GetSamlDownPartyAsync(name); }; Func <string, Task> postAction = async(name) => { var baseUrl = "https://localhost:44343"; var samlUpParty = new SamlDownParty { Name = name, Issuer = "urn:itfoxtec:idservice:samples:aspnetcoresamlsample", AllowUpPartyNames = new[] { loginName, aspNetCoreSamlIdPSampleUpPartyName, identityserverOidcOpUpPartyName /*, "foxids_oidcpkce", "adfs_saml_idp"*/ }, Keys = new[] { GetSamlCertificateKey("AspNetCoreSamlSample-test-sign-cert.crt") }, SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", CertificateValidationMode = X509CertificateValidationMode.None, RevocationMode = X509RevocationMode.NoCheck, AuthnRequestBinding = SamlBindingTypes.Redirect, AuthnResponseBinding = SamlBindingTypes.Post, AcsUrls = new[] { UrlCombine.Combine(baseUrl, "saml/assertionconsumerservice") }, LogoutRequestBinding = SamlBindingTypes.Post, LogoutResponseBinding = SamlBindingTypes.Post, SingleLogoutUrl = UrlCombine.Combine(baseUrl, "saml/singlelogout"), LoggedOutUrl = UrlCombine.Combine(baseUrl, "saml/loggedout"), Claims = new string[] { ClaimTypes.Email, ClaimTypes.Name, ClaimTypes.GivenName, ClaimTypes.Surname, ClaimTypes.Role }, SubjectConfirmationLifetime = 300, // 5 minutes IssuedTokenLifetime = 36000 // 10 hours }; await foxIDsApiClient.PostSamlDownPartyAsync(samlUpParty); }; await CreateIfNotExistsAsync(aspNetCoreSamlSampleDownPartyName, getAction, postAction); }
private LogoutRequest GetSamlLogoutRequest(SamlDownParty party, Saml2LogoutRequest saml2LogoutRequest) { var samlClaims = new List <Claim>(); if (saml2LogoutRequest.NameId != null) { samlClaims.AddClaim(Saml2ClaimTypes.NameId, saml2LogoutRequest.NameId.Value); if (saml2LogoutRequest.NameId.Format != null) { samlClaims.AddClaim(Saml2ClaimTypes.NameIdFormat, saml2LogoutRequest.NameId.Format.OriginalString); } } return(new LogoutRequest { DownPartyLink = new DownPartySessionLink { SupportSingleLogout = !string.IsNullOrWhiteSpace(party.SingleLogoutUrl), Id = party.Id, Type = party.Type }, SessionId = saml2LogoutRequest.SessionIndex, RequireLogoutConsent = false, PostLogoutRedirect = true, Claims = samlClaims, }); }
public async Task UpdateSamlDownPartyAsync(SamlDownParty party) => await PutAsync(samlApiUri, party);
public async Task CreateSamlDownPartyAsync(SamlDownParty party) => await PostAsync(samlApiUri, party);
public async Task <SamlDownParty> UpdateSamlDownPartyAsync(SamlDownParty party) => await PutResponseAsync <SamlDownParty, SamlDownParty>(samlApiUri, party);
private IEnumerable <Claim> GetSubjectClaims(SamlDownParty party, IEnumerable <Claim> claims) { IEnumerable <string> acceptedClaims = Constants.DefaultClaims.SamlClaims.ConcatOnce(party.Claims); return(claims.Where(c => acceptedClaims.Any(ic => ic == c.Type))); }
private SamlDownPartyViewModel ToViewModel(GeneralSamlDownPartyViewModel generalSamlDownParty, SamlDownParty samlDownParty) { return(samlDownParty.Map <SamlDownPartyViewModel>(afterMap => { generalSamlDownParty.KeyInfoList.Clear(); if (afterMap.Keys?.Count() > 0) { foreach (var key in afterMap.Keys) { generalSamlDownParty.KeyInfoList.Add(new KeyInfoViewModel { Subject = key.CertificateInfo.Subject, ValidFrom = key.CertificateInfo.ValidFrom, ValidTo = key.CertificateInfo.ValidTo, Thumbprint = key.CertificateInfo.Thumbprint, Key = key }); } } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } })); }