/// <summary> /// Gets the certificate specifications. /// </summary> /// <param name="endpoint">The endpoint.</param> /// <returns>A list of certificate validation specifications for this endpoint</returns> public static List<ICertificateSpecification> GetCertificateSpecifications(IdentityProvider endpoint) { var specs = new List<ICertificateSpecification>(); if (endpoint.CertificateValidationTypes != null && endpoint.CertificateValidationTypes.Count > 0) { foreach (var elem in endpoint.CertificateValidationTypes) { try { var val = (ICertificateSpecification)Activator.CreateInstance(Type.GetType(elem)); specs.Add(val); } catch (Exception e) { Logging.LoggerProvider.LoggerFor(typeof(SpecificationFactory)).Error(e.Message, e); } } } if (specs.Count == 0) { // Add default specification specs.Add(new DefaultCertificateSpecification()); } return specs; }
/// <summary> /// Gets the trusted signers. /// </summary> /// <param name="keys">The keys.</param> /// <param name="identityProvider">The identity provider.</param> /// <returns>List of trusted certificate signers.</returns> public static IEnumerable<AsymmetricAlgorithm> GetTrustedSigners(ICollection<KeyDescriptor> keys, IdentityProvider identityProvider) { if (keys == null) { throw new ArgumentNullException("keys"); } foreach (var clause in keys.SelectMany(k => k.KeyInfo.Items.AsEnumerable().Cast<KeyInfoClause>())) { // Check certificate specifications if (clause is KeyInfoX509Data) { var cert = XmlSignatureUtils.GetCertificateFromKeyInfo((KeyInfoX509Data)clause); if (!CertificateSatisfiesSpecifications(identityProvider, cert)) { continue; } } var key = XmlSignatureUtils.ExtractKey(clause); yield return key; } }
private static IdentityProviderEndpoint ConfigureRequest(IdentityProvider identityProvider, Saml20AuthnRequest request, HttpContext context) { // Set the last IDP we attempted to login at. if (context.Session != null) { context.Session[IdpTempSessionKey] = identityProvider.Id; } context.Items[IdpTempSessionKey] = identityProvider.Id; // Determine which endpoint to use from the configuration file or the endpoint metadata. var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultSignOnEndpoint, identityProvider.Metadata.SSOEndpoints); request.Destination = destination.Url; if (identityProvider.ForceAuth) { request.ForceAuthn = true; } // Check isPassive status var isPassiveFlag = context.Session != null ? context.Session[IdpIsPassive] : null; if (isPassiveFlag != null && (bool)isPassiveFlag) { request.IsPassive = true; context.Session[IdpIsPassive] = null; } if (identityProvider.IsPassive) { request.IsPassive = true; } // Check if request should forceAuthn var forceAuthnFlag = context.Session != null ? context.Session[IdpForceAuthn] : null; if (forceAuthnFlag != null && (bool)forceAuthnFlag) { request.ForceAuthn = true; context.Session[IdpForceAuthn] = null; } // Check if protocol binding should be forced if (identityProvider.Endpoints.DefaultSignOnEndpoint != null) { if (!string.IsNullOrEmpty(identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding; } } Utility.AddExpectedResponse(request, SessionToDictionary(context.Session)); return destination; }
/// <summary> /// Transfers the client. /// </summary> /// <param name="identityProvider">The identity provider.</param> /// <param name="request">The request.</param> /// <param name="context">The context.</param> private void TransferClient(IdentityProvider identityProvider, Saml20AuthnRequest request, HttpContext context, Saml2Configuration config) { IdentityProviderEndpoint destination = ConfigureRequest(identityProvider, request, context); switch (destination.Binding) { case BindingType.Redirect: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect); var redirectBuilder = new HttpRedirectBindingBuilder { SigningKey = _certificate.PrivateKey, Request = request.GetXml().OuterXml }; Logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery(); context.Response.Redirect(redirectLocation, true); break; case BindingType.Post: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost); var postBuilder = new HttpPostBindingBuilder(destination); // Honor the ForceProtocolBinding and only set this if it's not already set if (string.IsNullOrEmpty(request.ProtocolBinding)) { request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost; } var requestXml = request.GetXml(); XmlSignatureUtils.SignDocument(requestXml, request.Id, config.ServiceProvider.SigningCertificate); postBuilder.Request = requestXml.OuterXml; Logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request); context.Response.Write(postBuilder.GetPage()); break; case BindingType.Artifact: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact); var artifactBuilder = GetBuilder(context); // Honor the ForceProtocolBinding and only set this if it's not already set if (string.IsNullOrEmpty(request.ProtocolBinding)) { request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact; } Logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml); artifactBuilder.RedirectFromLogin(destination, request, context.Request.Params["relayState"], (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration)); break; default: Logger.Error(ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid); } }
/// <summary> /// Transfers the client. /// </summary> /// <param name="idp">The identity provider.</param> /// <param name="context">The context.</param> private void TransferClient(IdentityProvider idp, HttpContext context, Saml2Configuration config) { var request = Saml20LogoutRequest.GetDefault(config); // Determine which endpoint to use from the configuration file or the endpoint metadata. var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints); request.Destination = destination.Url; var nameIdFormat = (string)context.Session[IdpNameIdFormat]; request.SubjectToLogOut.Format = nameIdFormat; // Handle POST binding if (destination.Binding == BindingType.Post) { var builder = new HttpPostBindingBuilder(destination); request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; var requestDocument = request.GetXml(); XmlSignatureUtils.SignDocument(requestDocument, request.Id, config.ServiceProvider.SigningCertificate); builder.Request = requestDocument.OuterXml; Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "POST", builder.Request); context.Response.Write(builder.GetPage()); context.Response.End(); return; } // Handle Redirect binding if (destination.Binding == BindingType.Redirect) { request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; var builder = new HttpRedirectBindingBuilder { Request = request.GetXml().OuterXml, SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey }; var redirectUrl = destination.Url + (destination.Url.Contains("?") ? "&" : "?") + builder.ToQuery(); Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "REDIRECT", redirectUrl); context.Response.Redirect(redirectUrl, true); return; } // Handle Artifact binding if (destination.Binding == BindingType.Artifact) { request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "ARTIFACT", request.GetXml().OuterXml); var builder = GetBuilder(context); builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"), (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration)); } Logger.Error(ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid); }
/// <summary> /// Get configuration from config file. /// </summary> /// <returns>A configured <see cref="Saml2Config"/> instance.</returns> public static Saml2Config GetConfig() { var section = GetConfigElement(); var config = new Saml2Config(); // Actions if (section.Actions.ElementInformation.IsPresent) { foreach (var action in section.Actions) { config.Actions.Add(new Action { Name = action.Name, Type = action.Type }); } } // Allowed Audience URIs if (section.AllowedAudienceUris.ElementInformation.IsPresent) { foreach (var allowedAudienceUri in section.AllowedAudienceUris) { config.AllowedAudienceUris.Add(allowedAudienceUri.Uri); } } // Assertion profile if (section.AssertionProfile.ElementInformation.IsPresent) { config.AssertionProfile.AssertionValidator = section.AssertionProfile.AssertionValidator; } // Common domain cookie if (section.CommonDomainCookie.ElementInformation.IsPresent) { config.CommonDomainCookie.Enabled = section.CommonDomainCookie.Enabled; config.CommonDomainCookie.LocalReaderEndpoint = section.CommonDomainCookie.LocalReaderEndpoint; } // Identity Providers if (section.IdentityProviders.ElementInformation.IsPresent) { config.IdentityProviderSelectionUrl = section.IdentityProviders.SelectionUrl; config.IdentityProviders.Encodings = section.IdentityProviders.Encodings; config.IdentityProviders.MetadataLocation = section.IdentityProviders.MetadataLocation; foreach (var identityProvider in section.IdentityProviders) { var idp = new IdentityProvider { AllowUnsolicitedResponses = identityProvider.AllowUnsolicitedResponses, Default = identityProvider.Default, ForceAuth = identityProvider.ForceAuth, Id = identityProvider.Id, IsPassive = identityProvider.IsPassive, Name = identityProvider.Name, OmitAssertionSignatureCheck = identityProvider.OmitAssertionSignatureCheck, QuirksMode = identityProvider.QuirksMode, ResponseEncoding = identityProvider.ResponseEncoding }; if (identityProvider.ArtifactResolution.ElementInformation.IsPresent) { var artifactResolution = new HttpAuth(); if (identityProvider.ArtifactResolution.ClientCertificate.ElementInformation.IsPresent) { artifactResolution.ClientCertificate = new Certificate { FindValue = identityProvider.ArtifactResolution.ClientCertificate.FindValue, StoreLocation = identityProvider.ArtifactResolution.ClientCertificate.StoreLocation, StoreName = identityProvider.ArtifactResolution.ClientCertificate.StoreName, ValidOnly = identityProvider.ArtifactResolution.ClientCertificate.ValidOnly, X509FindType = identityProvider.ArtifactResolution.ClientCertificate.X509FindType }; } if (identityProvider.ArtifactResolution.Credentials.ElementInformation.IsPresent) { artifactResolution.Credentials = new HttpAuthCredentials { Password = identityProvider.ArtifactResolution.Credentials.Password, Username = identityProvider.ArtifactResolution.Credentials.Username }; } idp.ArtifactResolution = artifactResolution; } if (identityProvider.AttributeQuery.ElementInformation.IsPresent) { var attributeQuery = new HttpAuth(); if (identityProvider.AttributeQuery.ClientCertificate.ElementInformation.IsPresent) { attributeQuery.ClientCertificate = new Certificate { FindValue = identityProvider.AttributeQuery.ClientCertificate.FindValue, StoreLocation = identityProvider.AttributeQuery.ClientCertificate.StoreLocation, StoreName = identityProvider.AttributeQuery.ClientCertificate.StoreName, ValidOnly = identityProvider.AttributeQuery.ClientCertificate.ValidOnly, X509FindType = identityProvider.AttributeQuery.ClientCertificate.X509FindType }; } if (identityProvider.AttributeQuery.Credentials.ElementInformation.IsPresent) { attributeQuery.Credentials = new HttpAuthCredentials { Password = identityProvider.AttributeQuery.Credentials.Password, Username = identityProvider.AttributeQuery.Credentials.Username }; } idp.AttributeQuery = attributeQuery; } if (identityProvider.PersistentPseudonym.ElementInformation.IsPresent) { idp.PersistentPseudonym = new PersistentPseudonym { Mapper = identityProvider.PersistentPseudonym.Mapper }; } foreach (var certificateValidation in identityProvider.CertificateValidations) { idp.CertificateValidations.Add(certificateValidation.Type); } foreach (var key in identityProvider.CommonDomainCookie.AllKeys) { idp.CommonDomainCookie.Add(identityProvider.CommonDomainCookie[key].Key, identityProvider.CommonDomainCookie[key].Value); } foreach (var endpoint in identityProvider.Endpoints) { idp.Endpoints.Add(new IdentityProviderEndpoint { Binding = endpoint.Binding, ForceProtocolBinding = endpoint.ForceProtocolBinding, TokenAccessor = endpoint.TokenAccessor, Type = endpoint.Type, Url = endpoint.Url }); } config.IdentityProviders.Add(idp); } } // Logging config if (section.Logging.ElementInformation.IsPresent) { config.Logging.LoggingFactory = section.Logging.LoggingFactory; } // Metadata config if (section.Metadata.ElementInformation.IsPresent) { config.Metadata.ExcludeArtifactEndpoints = section.Metadata.ExcludeArtifactEndpoints; config.Metadata.Lifetime = section.Metadata.Lifetime; if (section.Metadata.Organization.ElementInformation.IsPresent) { config.Metadata.Organization = new Organization { Name = section.Metadata.Organization.Name, DisplayName = section.Metadata.Organization.DisplayName, Url = section.Metadata.Organization.Url }; } foreach (var contact in section.Metadata.Contacts) { config.Metadata.Contacts.Add(new Contact { Company = contact.Company, Email = contact.Email, GivenName = contact.GivenName, Phone = contact.Phone, SurName = contact.SurName, Type = contact.Type }); } foreach (var attribute in section.Metadata.RequestedAttributes) { config.Metadata.RequestedAttributes.Add(new Attribute { IsRequired = attribute.IsRequired, Name = attribute.Name }); } } // Service provider if (section.ServiceProvider.ElementInformation.IsPresent) { config.ServiceProvider.AuthenticationContextComparison = section.ServiceProvider.AuthenticationContexts.Comparison; config.ServiceProvider.Id = section.ServiceProvider.Id; config.ServiceProvider.NameIdFormatAllowCreate = section.ServiceProvider.NameIdFormats.AllowCreate; config.ServiceProvider.Server = section.ServiceProvider.Server; if (section.ServiceProvider.SigningCertificate.ElementInformation.IsPresent) { config.ServiceProvider.SigningCertificate = new Certificate { FindValue = section.ServiceProvider.SigningCertificate.FindValue, StoreLocation = section.ServiceProvider.SigningCertificate.StoreLocation, StoreName = section.ServiceProvider.SigningCertificate.StoreName, ValidOnly = section.ServiceProvider.SigningCertificate.ValidOnly, X509FindType = section.ServiceProvider.SigningCertificate.X509FindType }; } foreach (var authContext in section.ServiceProvider.AuthenticationContexts) { config.ServiceProvider.AuthenticationContexts.Add(new AuthenticationContext { Context = authContext.Context, ReferenceType = authContext.ReferenceType }); } foreach (var endpoint in section.ServiceProvider.Endpoints) { config.ServiceProvider.Endpoints.Add(new ServiceProviderEndpoint { Binding = endpoint.Binding, Index = endpoint.Index, LocalPath = endpoint.LocalPath, RedirectUrl = endpoint.RedirectUrl, Type = endpoint.Type }); } foreach (var nameIdFormat in section.ServiceProvider.NameIdFormats) { config.ServiceProvider.NameIdFormats.Add(nameIdFormat.Format); } } // State config if (section.State.ElementInformation.IsPresent) { config.State.StateServiceFactory = section.State.StateServiceFactory; foreach (var setting in section.State.Settings) { config.State.Settings.Add(setting.Name, setting.Value); } } return(config); }
private string AuthnRequestForIdp(IdentityProvider identityProvider, Saml20AuthnRequest request, IOwinContext context, Saml2Configuration config) { var logger = SAML2.Logging.LoggerProvider.LoggerFor(typeof(SamlMessage)); context.Set(IdpTempSessionKey, identityProvider.Id); // Determine which endpoint to use from the configuration file or the endpoint metadata. var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultSignOnEndpoint, identityProvider.Metadata.SSOEndpoints); request.Destination = destination.Url; if (identityProvider.ForceAuth) { request.ForceAuthn = true; } // Check isPassive status if (context.Get<bool>(IdpIsPassive)) { request.IsPassive = true; } if (identityProvider.IsPassive) { request.IsPassive = true; } // Check if request should forceAuthn if (context.Get<bool>(IdpForceAuthn)) { request.ForceAuthn = true; } // Check if protocol binding should be forced if (identityProvider.Endpoints.DefaultSignOnEndpoint != null) { if (!string.IsNullOrEmpty(identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding; } } // Save request message id to session Utility.AddExpectedResponseId(request.Id); switch (destination.Binding) { case BindingType.Redirect: logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect); var redirectBuilder = new HttpRedirectBindingBuilder { SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey, Request = request.GetXml().OuterXml }; if (context.Authentication != null && context.Authentication.AuthenticationResponseChallenge != null && context.Authentication.AuthenticationResponseChallenge.Properties != null && context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary != null && context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.Count > 0) redirectBuilder.RelayState = context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.ToDelimitedString(); logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery(); return redirectLocation; case BindingType.Post: throw new NotImplementedException(); //logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost); //var postBuilder = new HttpPostBindingBuilder(destination); //// Honor the ForceProtocolBinding and only set this if it's not already set //if (string.IsNullOrEmpty(request.ProtocolBinding)) { // request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost; //} //var requestXml = request.GetXml(); //XmlSignatureUtils.SignDocument(requestXml, request.Id, config.ServiceProvider.SigningCertificate); //postBuilder.Request = requestXml.OuterXml; //logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request); //context.Response.Write(postBuilder.GetPage()); //break; case BindingType.Artifact: throw new NotImplementedException(); //logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact); //var artifactBuilder = new HttpArtifactBindingBuilder(context, config); //// Honor the ForceProtocolBinding and only set this if it's not already set //if (string.IsNullOrEmpty(request.ProtocolBinding)) { // request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact; //} //logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml); //artifactBuilder.RedirectFromLogin(destination, request); //break; default: logger.Error(SAML2.ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(SAML2.ErrorMessages.EndpointBindingInvalid); } throw new NotImplementedException(); }
/// <summary> /// Determines whether the certificate is satisfied by all specifications. /// </summary> /// <param name="idp">The identity provider.</param> /// <param name="cert">The cert.</param> /// <returns><c>true</c> if certificate is satisfied by all specifications; otherwise, <c>false</c>.</returns> private static bool CertificateSatisfiesSpecifications(IdentityProvider idp, X509Certificate2 cert) { return SpecificationFactory.GetCertificateSpecifications(idp).All(spec => spec.IsSatisfiedBy(cert)); }
/// <summary> /// Is called before the assertion is made into a strongly typed representation /// </summary> /// <param name="elem">The assertion element.</param> /// <param name="endpoint">The endpoint.</param> /// public static void PreHandleAssertion(XmlElement elem, IdentityProvider endpoint) { logger.DebugFormat(TraceMessages.AssertionPrehandlerCalled); if (endpoint != null && endpoint.Endpoints.DefaultLogoutEndpoint != null && !string.IsNullOrEmpty(endpoint.Endpoints.DefaultLogoutEndpoint.TokenAccessor)) { var idpTokenAccessor = Activator.CreateInstance(Type.GetType(endpoint.Endpoints.DefaultLogoutEndpoint.TokenAccessor, false)) as ISaml20IdpTokenAccessor; if (idpTokenAccessor != null) { logger.DebugFormat("{0}.{1} called", idpTokenAccessor.GetType(), "ReadToken"); idpTokenAccessor.ReadToken(elem); logger.DebugFormat("{0}.{1} finished", idpTokenAccessor.GetType(), "ReadToken"); } } }