Как программно отправить WS-Trust ActAs через клиентский прокси WCF с привязкой федерации - PullRequest
0 голосов
/ 16 февраля 2020

Поставщик услуг обновил службу проверяющей стороны и требует отправки параметров 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">
...