我正在尝试执行以下操作:
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>
因此我觉得WCF正试图联系STS发出令牌。正确?
我不希望WCF从STS获取令牌,我想提供自己的令牌。
问题/问题:
这是我用于测试的代码:
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()
忘记在代码中创建SAML令牌的部分。
用户从身份验证提供程序验证并接收SAML令牌。稍后用户访问URL,Web应用程序需要对服务进行SOAP调用以获取用户需要的数据。
所以让我们在这个上下文中重新解释这个问题:Web应用程序(使用WCF)如何对Web服务进行SOAP调用并包含用户登录时提供的SAML令牌?
答案 0 :(得分:1)
您尝试做的事情从根本上违背了联邦身份的概念。如果您组装自己的令牌,那么它看起来就像伪造的令牌,因为它是。令牌需要来自auth服务器,并因此针对auth服务器(或联合中的成员服务器)进行检查。
编辑:如果您希望Web服务器重用该标识,则可以使用相同的限制来调用Web服务。考虑一下这些影响,如果Web服务器可以作为中继凭据的代理,这将是一个非常严重的安全警告。这相当于一个中间人攻击。 OAuth2应该可以阻止这类事情。
因此,解决方案是编写应用程序,以便客户端计算机(已经过身份验证)可以直接联系Web服务。从架构和设计的角度来看,这很麻烦,但这就是它的工作方式。它可能解释了最近流行的JS框架(JQuery,Angular等)。