/// <summary> /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The logout request.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request, string relayState) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState); }
/// <summary> /// Creates an artifact and redirects the user to the IdP /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The authentication request.</param> public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request) { var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Creates an artifact and redirects the user to the IdP /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The authentication request.</param> /// <param name="relayState">Relay state from client. May be null</param> public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request, string relayState, Action <string, object> cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action <string, object> cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID, config); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response) { var config = Saml2Config.Current; var index = (short)config.ServiceProvider.LogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Determine which endpoint to use based on the protocol defaults, configuration data and metadata. /// </summary> /// <param name="defaultBinding">The binding to use if none has been specified in the configuration and the metadata allows all bindings.</param> /// <param name="config">The endpoint as described in the configuration. May be null.</param> /// <param name="metadata">A list of endpoints of the given type (e.g. SSO or SLO) that the metadata contains.</param> /// <returns>The <see cref="IdentityProvider"/>.</returns> public static IdentityProviderEndpoint DetermineEndpointConfiguration(BindingType defaultBinding, IdentityProviderEndpoint config, List <IdentityProviderEndpoint> metadata) { var result = new IdentityProviderEndpoint { Binding = defaultBinding }; // Determine which binding to use. if (config != null) { result.Binding = config.Binding; } else { // Verify that the metadata allows the default binding. var allowed = metadata.Exists(el => el.Binding == defaultBinding); if (!allowed) { result.Binding = result.Binding == BindingType.Post ? BindingType.Redirect : BindingType.Post; } } if (config != null && !string.IsNullOrEmpty(config.Url)) { result.Url = config.Url; } else { var endpoint = metadata.Find(el => el.Binding == result.Binding); if (endpoint == null) { throw new FormatException(string.Format("No IdentityProvider supporting SAML binding {0} found in metadata", result.Binding)); } result.Url = endpoint.Url; } return(result); }
/// <summary> /// Handles all artifact creations and redirects. /// </summary> /// <param name="destination">The destination.</param> /// <param name="localEndpointIndex">Index of the local endpoint.</param> /// <param name="signedSamlMessage">The signed SAML message.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState) { Logger.DebugFormat(TraceMessages.ArtifactRedirectReceived, signedSamlMessage.OuterXml); var sourceId = config.ServiceProvider.Id; var sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId); var messageHandle = ArtifactUtil.GenerateMessageHandle(); var artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); Context.Cache.Insert(artifact, signedSamlMessage, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration); var destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + HttpUtility.UrlEncode(artifact); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; } Logger.DebugFormat(TraceMessages.ArtifactCreated, artifact); Context.Response.Redirect(destinationUrl); }
/// <summary> /// Handles all artifact creations and redirects. /// </summary> /// <param name="destination">The destination.</param> /// <param name="localEndpointIndex">Index of the local endpoint.</param> /// <param name="signedSamlMessage">The signed SAML message.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState, Action <string, object> cacheInsert) { _logger.LogDebug(TraceMessages.ArtifactRedirectReceived, signedSamlMessage.OuterXml); var sourceId = config.ServiceProvider.Id; var sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId); var messageHandle = ArtifactUtil.GenerateMessageHandle(); var artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); cacheInsert(artifact, signedSamlMessage); var destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + Uri.EscapeDataString(artifact); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; } _logger.LogDebug(TraceMessages.ArtifactCreated, artifact); redirect(destinationUrl); }
/// <summary> /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The logout request.</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request) { RedirectFromLogout(destination, request, Context.Request.Params["relayState"]); }
/// <summary> /// Initializes a new instance of the <see cref="HttpPostBindingBuilder"/> class. /// </summary> /// <param name="endpoint">The IdP endpoint that messages will be sent to.</param> public HttpPostBindingBuilder(IdentityProviderEndpoint endpoint) { _destinationEndpoint = endpoint; Action = SamlActionType.SAMLRequest; RelayState = string.Empty; }
/// <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 + (request.Destination.Contains("?") ? "&" : "?") + 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.PostSimpleSign: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPostSimpleSign); var postSimpleSignBuilder = 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.HttpPostSimpleSign; } var requestXmlSimpleSign = request.GetXml(); XmlSignatureUtils.SignDocument(requestXmlSimpleSign, request.Id, config.ServiceProvider.SigningCertificate); postSimpleSignBuilder.Request = requestXmlSimpleSign.OuterXml; Logger.DebugFormat(TraceMessages.AuthnRequestSent, postSimpleSignBuilder.Request); context.Response.Write(postSimpleSignBuilder.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> /// Adds an <see cref="IdentityProviderEndpoint"/> to the config. /// </summary> /// <param name="endpoint">The <see cref="IdentityProviderEndpoint"/> to add.</param> /// <returns>The <see cref="ServiceProviderConfigBuilder"/>.</returns> public IdentityProviderBuilder AddEndpoint(IdentityProviderEndpoint endpoint) { _endpoints.Add(endpoint); return(this); }