无法通过 HTTP post 接收 SAML 响应

Failed to receive SAML response by HTTP post

在 SSO 实施中,验证用户后,我创建了一个 SAMLResponse 对象并使用 IdentityProvider.SendSAMLResponseByHTTPPost() 方法将其发布到默认登陆 URL。

IdentityProvider.SendSAMLResponseByHTTPPost(Response, strAssertionConsumerServiceURL, samlResponseXml, relayState);

samlResponseXml - 包含 SAML 请求 XML

在 ServiceProvider.ReceiveSAMLResponseByHTTPPost() 方法上,我得到以下捕获异常。

Failed to receive SAML response by HTTP post

身份提供者和服务提供者都在同一个网络域中。

附上 ComponentSpace.SAML2 的日志

ComponentSpace.SAML2 Verbose: 0 : 9:19:44 PM: Missing form variable SAMLResponse
ComponentSpace.SAML2 Verbose: 0 : 9:19:44 PM: Exception: ComponentSpace.SAML2.SAMLBindingException: The form is missing the variable SAMLResponse
ComponentSpace.SAML2 Verbose: 0 : 9:19:44 PM: Exception: ComponentSpace.SAML2.SAMLBindingException: Failed to receive response over HTTP POST. ---> ComponentSpace.SAML2.SAMLBindingException: The form is missing the variable SAMLResponse
   at ComponentSpace.SAML2.Bindings.HTTPPostBinding.GetFormVariables(HttpRequest httpRequest, String messageFormVariableName, XmlElement& samlMessage, String& relayState)
   at ComponentSpace.SAML2.Bindings.HTTPPostBinding.ReceiveResponse(HttpRequest httpRequest, XmlElement& samlMessage, String& relayState)
   --- End of inner exception stack trace ---

问题:
(1) 无法通过 HTTP post

接收 SAML 响应

(2)

ComponentSpace.SAML2 Verbose: 0 : 9:19:44 PM: Missing form variable SAMLResponse
ComponentSpace.SAML2 Verbose: 0 : 9:19:44 PM: Exception: ComponentSpace.SAML2.SAMLBindingException: The form is missing the variable SAMLResponse

分辨率:

SAML 异常日志指出 SAML 响应的 form/format 不正确。

Creating SAML Response for SSO提供以下示例代码来演示如何使用 ComponentSpace 库生成 SAML 响应。

        // Create a SAML response with the user's local identity.
        private SAMLResponse CreateSAMLResponse()
        {
            //Trace.Write("IdPreating SAML response");
           SAMLResponse samlResponse = new SAMLResponse();
            samlResponse.Destination = strAssertionConsumerServiceURL;
            Issuer issuer = new Issuer(CreateAbsoluteURL("~/"));
            samlResponse.Issuer = issuer;
            samlResponse.Status = new Status(SAMLIdentifiers.PrimaryStatusCodes.Success, null);
            SAMLAssertion samlAssertion = new SAMLAssertion();
            samlAssertion.Issuer = issuer;
            //Subject subject = new Subject(new NameID(User.Identity.Name));
            Subject subject = new Subject(new NameID());
            SubjectConfirmation subjectConfirmation = new SubjectConfirmation(SAMLIdentifiers.SubjectConfirmationMethods.Bearer);
            SubjectConfirmationData subjectConfirmationData = new SubjectConfirmationData();
            subjectConfirmationData.Recipient = strAssertionConsumerServiceURL;
            subjectConfirmation.SubjectConfirmationData = subjectConfirmationData;
            subject.SubjectConfirmations.Add(subjectConfirmation);
            samlAssertion.Subject = subject;
            samlAssertion.SetAttributeValue("MemberId", this.txtMemberId.Text);
            samlAssertion.SetAttributeValue("Name", this.txtName.Text);
            samlAssertion.SetAttributeValue("Phone", this.txtPhone.Text);
            AuthnStatement authnStatement = new AuthnStatement();
            authnStatement.AuthnContext = new AuthnContext();
            authnStatement.AuthnContext.AuthnContextClassRef = new AuthnContextClassRef(SAMLIdentifiers.AuthnContextClasses.Password);
            samlAssertion.Statements.Add(authnStatement);
           samlResponse.Assertions.Add(samlAssertion);
            return samlResponse;
        }
        // Send the SAML response to the SP.
        private void SendSAMLResponse(SAMLResponse samlResponse, string relayState)
        {
            // Serialize the SAML response for transmission.
            XmlElement samlResponseXml = samlResponse.ToXml();
            // Sign the SAML response.
           X509Certificate2 x509Certificate = (X509Certificate2)Application["IdPX509Certificate"];
            SAMLMessageSignature.Generate(samlResponseXml, x509Certificate.PrivateKey, x509Certificate);
          IdentityProvider.SendSAMLResponseByHTTPPost(Response, strAssertionConsumerServiceURL, samlResponseXml, relayState);
        }

在使用 Firebug 控制台和 Fiddler2 进行多次尝试后,已确定当我尝试将数据发布到 AssertionConsumerServiceURL 页面时调用了 Http GET,尽管使用了 SendSAMLResponseByHTTPPost() 和 ReceiveSAMLResponseByHTTPPost()。

 string strAssertionConsumerServiceURL = "http://localhost:58986/AssertionInternal.aspx";

上面的 AssertionConsumer 服务 url 被修改为如下,

 string strAssertionConsumerServiceURL = "http://localhost:58986/AssertionInternal";

有了这个 URL,SAML POST 数据已成功接收。

指定 URL 扩展名为 .aspx 在我的应用程序中调用 GET Verb 而不是 POST 动词