Поставщик услуг обновил службу проверяющей стороны и требует отправки параметров ActAs в STS в запросе маркера безопасности. Эти значения ActAs будут варьироваться в зависимости от запроса, поэтому значения будут определены в коде при выполнении запроса. В существующем приложении есть клиентский прокси WCF, созданный с помощью Service Reference и настроенный на использование ws2007FederationHttpBinding
для обработки запроса на токен безопасности. Как параметры Act-WS-Trust можно присоединить к исходящему запросу STS (который прозрачно обрабатывается WCF)?
Параметры ActAs имеют следующую структуру:
<RequestSecurityToken xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<tr:ActAs xmlns:tr="http://docs.oasis-open.org/ws-sx/ws-trust/200802">
<v13:RelationshipToken ID="1a98e000-fd23-4bde-934b-4d1d1000cd1d" xmlns:v13="http://someuri/2020/01">
<v13:Relationship v13:Type="Provider">
<v13:Attribute v13:Name="ID" v13:Value="012345"></v13:Attribute>
</v13:Relationship>
<v13:FirstParty v13:Scheme="uri://anotheruri/Identifier" v13:Value="056789"></v13:FirstParty>
<v13:SecondParty v13:Scheme="uri://anotheruri/Identifier" v13:Value="083453"></v13:SecondParty>
</v13:RelationshipToken>
</tr:ActAs>
<wst:RequestType xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>
<wst:TokenType xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</wst:TokenType>
</RequestSecurityToken>
Существующая конфигурация клиента:
<system.serviceModel>
<client>
<endpoint address="https://the_actual_service_relying_party/TheService.svc" binding="ws2007FederationHttpBinding" bindingConfiguration="WS2007FederationHttpBinding_ITheService" contract="ITheService" name="WS2007FederationHttpBinding_ITheService"/>
</client>
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_TheService">
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false">
<issuer address="https://the_security_token_service/Service.svc" binding="ws2007HttpBinding" bindingConfiguration="https://the_security_token_service/Service.svc" />
<issuerMetadata address="https://the_security_token_service/Service.svc/mex" />
<tokenRequestParameters>
<trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
<trust:KeySize>256</trust:KeySize>
<trust:KeyWrapAlgorithm>http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
<trust:Claims Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity"
xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity">
<!-- custom claims omitted -->
</trust:Claims>
<trust:EncryptWith>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
<trust:SignWith>http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
<trust:CanonicalizationAlgorithm>http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
<trust:EncryptionAlgorithm>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
</trust:SecondaryParameters>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="https://the_security_token_service/Service.svc">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="Certificate" algorithmSuite="Basic256Sha256Rsa15" establishSecurityContext="false" />
</security>
</binding>
</ws2007HttpBinding
</bindings>
</system.serviceModel>
Существующий код клиента:
var endpointConfigurationName = "WS2007FederationHttpBinding_ITheService";
var channelFactory = new ChannelFactory<ITheService>(endpointConfigurationName);
var endpointBehaviour = (ClientCredentials)channelFactory.Endpoint.Behaviors[typeof(ClientCredentials)];
endpointBehaviour.ClientCertificate.Certificate = GetX509Certificate2();
var client = channelFactory.CreateChannel();
// This works and receives a valid token from the STS before calling the relying party service,
// but how to send ActAs parameters in the initial STS request?
client.ValidateData(new ValidateDataRequest());
Испытанные подходы:
Подход 1 - Используйте IClientMessageInspector для перехвата исходящего запроса на ручное добавление необходимых элементов
Это будет только перехватывать последний вызов службы проверяющей стороны, а не начальный вызов STS.
channelFactory.Endpoint.EndpointBehaviors.Add(new ActAsBehavior());
public class ActAsBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint,
System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
var inspector = new ActAsInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
}
public class ActAsInspector : System.ServiceModel.Dispatcher.IClientMessageInspector
{
object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
// only raised on the final relying party call, not initial call to STS
}
}
Подход 2. Вызов STS напрямую через предоставленный SDK, а затем создание канала с помощью CreateChannelWithIssuedToken
Пользовательский SDK доступен с клиентом службы для получения токена от STS, но не для вызова проверяющей стороны. Полученный токен шифруется ключом проверяющей стороны. Попытка использовать этот токен с CreateChannelWithIssuedToken
не присоединяет токен к исходящему запросу SOAP (проверено с помощью трассировки сообщения WCF).
XmlElement encryptedSaml2Assertion = GetTokenFromSTS(); // get token via SDK here
var securityToken = new GenericXmlSecurityToken(encryptedSaml2Assertion, null, DateTime.Now, DateTime.Now.AddHours(1.0), null, null, null);
var channelFactory = new ChannelFactory<ITheService>("ws2007HttpBindingRelyingParty");
var client = channelFactory.CreateChannelWithIssuedToken(securityToken);
// outgoing SOAP request has no security token
client.ValidateData(new ValidateDataRequest());
Client.config для подхода 2 (все другие конечные точки закомментированы )
<ws2007HttpBinding>
<binding name="ws2007HttpBindingRelyingParty">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="IssuedToken" algorithmSuite="Basic256Sha256Rsa15" establishSecurityContext="false" />
</security>
</binding>
</ws2007HttpBinding>
<endpoint address="https://the_actual_service_relying_party/TheService.svc" binding="ws2007HttpBinding" bindingConfiguration="ws2007HttpBindingRelyingParty" contract="ITheService" name="ws2007HttpBindingRelyingParty">