.net 使用WCF使用SAML2令牌调用SOAP web服务

.net 使用WCF使用SAML2令牌调用SOAP web服务,.net,wcf,saml,saml-2.0,federated-identity,.net,Wcf,Saml,Saml 2.0,Federated Identity,我正在努力做到以下几点: 在代码中创建SAML2令牌 使用WCF,使用SOAP调用web服务并包含SAML2令牌 使用下面的代码,我尝试实现上述功能。我在localhost:9000上运行soapweb服务,并运行Fiddler来检查流量 现在,当我运行测试客户机时,我在var response=channel.CrossGatewayQuery()服务调用上得到一个异常(整个堆栈跟踪在问题的末尾) 例外情况: SecurityNegotiationException Inner exce

我正在努力做到以下几点:

  • 在代码中创建SAML2令牌
  • 使用WCF,使用SOAP调用web服务并包含SAML2令牌
  • 使用下面的代码,我尝试实现上述功能。我在localhost:9000上运行soapweb服务,并运行Fiddler来检查流量
  • 现在,当我运行测试客户机时,我在
    var response=channel.CrossGatewayQuery()
    服务调用上得到一个异常(整个堆栈跟踪在问题的末尾)
例外情况:

SecurityNegotiationException

Inner exception: Fault Exception
The message with Action 'http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue' cannot be processed at the receiver, 
due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions 
between sender and receiver) or a binding/security mismatch between the sender and the receiver.  Check that sender and receiver 
have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
Fiddler记录以下请求:

POST /RespondingGateway/ HTTP/1.1
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
        <a:MessageID>urn:uuid:3609d530-4b8d-4e9c-8907-bb346cfe0c91</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand="1">http://localhost:9000/RespondingGateway/</a:To>
    </s:Header>
    <s:Body>
        <t:RequestSecurityToken Context="uuid-e6928b4c-6100-4a1d-8818-8e7436f7a935-12" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
            <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
            <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
            <t:KeySize>256</t:KeySize>
            <t:BinaryExchange ValueType=" http://schemas.xmlsoap.org/ws/2005/02/trust/tlsnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">...</t:BinaryExchange>
        </t:RequestSecurityToken>
    </s:Body>
</s:Envelope>
在tgolisch的评论后更新 忘记关于在代码中创建SAML令牌的部分

用户进行身份验证并从身份验证提供程序接收SAML令牌。稍后,用户访问URL,web应用程序需要对服务进行SOAP调用,以获取用户需要的数据

因此,让我们在此上下文中重新表述这个问题:web应用程序(使用WCF)如何对web服务进行SOAP调用并包含用户登录时提供的SAML令牌

另见

您试图做的事情从根本上违背了联邦身份的概念。如果你组装了你自己的代币,那么它看起来就像是伪造的代币,因为它是伪造的。令牌需要来自身份验证服务器,并(因此)根据身份验证服务器(或联合体中的成员服务器)进行检查

编辑:如果希望web服务器在调用web服务时重用该标识,则同样的限制也适用。考虑一下这些影响,如果web服务器可以充当代理来中继凭据,这将是一个非常严重的安全警告。这相当于一个人在中间攻击。OAuth2应该阻止这种事情


因此,解决方案是编写应用程序,以便客户机(已通过身份验证)可以直接联系web服务。从架构和设计的角度来看,这是一个麻烦,但这就是它的工作方式。这可能解释了最近JS框架(JQuery、Angular等)的流行。

好吧,但是如果我有一个现有的SAML2令牌,我想重新使用该怎么办?例如,假设用户登录到我的web应用时我有一个SAML2令牌,以后web应用应使用登录SAML2令牌调用SOAP web服务。SAML2令牌存储在浏览器会话上的非持久性cookie中,但它绑定到发出它的域。如果您的web应用程序和SOAP服务器使用相同的身份验证服务器,那么只要身份验证服务器信任您的web应用程序和SOAP服务器,用户就应该能够对这两个服务器重复使用身份验证。好的,让我们先忘掉在代码中创建SAML令牌的部分。因此,web应用程序进行身份验证并从身份验证提供者接收SAML令牌。稍后,用户访问URL,web应用程序需要对服务进行SOAP调用,以获取用户需要的数据。因此,让我们在此上下文中重新表述这个问题:web应用程序(使用WCF)如何对web服务进行SOAP调用,并包括用户登录时提供的SAML令牌?您的WCF是在防火墙后面还是可以从客户端访问?您指的是服务吗?该服务不在防火墙后面,客户端可以通过网络访问该服务。
void SendRequest(XElement requestBody)
{
    var binding = new WSFederationHttpBinding();
    binding.Security.Mode = WSFederationHttpSecurityMode.Message;
    binding.Security.Message.IssuedTokenType = 
        "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0";

    var remoteAddress = 
        new EndpointAddress("http://localhost:9000/RespondingGateway/");
    var channelFactory = 
        new ChannelFactory<ICrossGatewayQueryITI38>(binding, remoteAddress);

    // if true I get a "Cardspace not installed" exception
    channelFactory.Credentials.SupportInteractive = false; 

    var channel = channelFactory.CreateChannelWithIssuedToken(
        CreateSaml2Token(
            GetCertificate(
                "thumbprint_of_certificate_i_have_private_key_of"
            )
        )
    );
    var response = channel.CrossGatewayQuery(CreateRequestMessage(requestBody));
    var body = XElement.ReadFrom(response.GetReaderAtBodyContents());
    Console.WriteLine(body.ToString());
}

Saml2SecurityToken CreateSaml2Token(X509Certificate2 certificate)
{
    var std = new SecurityTokenDescriptor();
    std.TokenIssuerName = "Foobar";
    std.TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0";
    std.Lifetime = new Lifetime(DateTime.Now, DateTime.Now + TimeSpan.FromDays(10));
    std.Subject = new ClaimsIdentity(new[] { new Claim("User", "TheUserName") });

    if (certificate != null)
    {
        var ski = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { new X509SecurityToken(certificate).CreateKeyIdentifierClause<X509SubjectKeyIdentifierClause>() });
        std.SigningCredentials = new X509SigningCredentials(certificate, ski); ;
    }
    return (Saml2SecurityToken)new Saml2SecurityTokenHandler().CreateToken(std);
}

Message CreateRequestMessage(XElement requestBody)
{
    return Message.CreateMessage(
        MessageVersion.Soap12WSAddressing10,
        "urn:ihe:iti:2007:CrossGatewayQuery",
        requestBody
    );
}

[ServiceContract(Namespace = "urn:ihe:iti:xds-b:2007")]
public interface ICrossGatewayQueryITI38
{
    [OperationContract(Action = "urn:ihe:iti:2007:CrossGatewayQuery", ReplyAction = "urn:ihe:iti:2007:CrossGatewayQueryResponse")]
    Message CrossGatewayQuery(Message request);
}
Server stack trace: 
   at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
   at System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
   at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
   at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
   at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
   at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at XDSDotNet.ICrossGatewayQueryITI38.CrossGatewayQuery(Message request)
   at UserQuery.SendRequest(XElement requestBody)
   at UserQuery.Main()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()