• Category Archives Development
  • How to consume a web service, through client certification and Oauth2 Authentication, writing c# code.

    Versione Italiana.
    Who has done similar task , using visual studio, knows the IDE helps the developers, providing some classes useful to easly call a webservice. If the developer has available the WSDL file defining the service, Visual studio parses it , and automatically builds the libraries

    But, if the call must use a channel, encrypted by a client certificate, and further the server expect an Oauth2 authentication token , enclosed in the request, the task becomes quite harder

    With C# it’s quite simple to make an HTTP request using a client certificate to make the call, on the same HTTP request and also simple to add the OAuth2 token among the Headers.
    If the request is simple (It has few parameters and is not structured on several levels), the developer can send a raw HTTP request, inserting the parameters in the body of this.
    If instead the parameters of the request are many and very structured, doing such a thing would take a lot of time.

    I found a way to use the libraries generated by Visual studio, on an encrypted channel and with the Oauth2 authentication token.

    Below, is the code that would be used for a call with the usual method:

    var Binding = new BasicHttpBinding();
    EndpointAddress ServiceEndPoint = new EndpointAddress("http://EndpointAddress.com");
    ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
    ServiceReference.ServiceResult result = client.Method(ServiceParameter);

    If you want to make the call on an encrypted channel, you must first create a certificate object:

    X509Certificate2 certificate = new X509Certificate2("filePath.p12", "Password");

    Where the file containing the certificate must be in p12 format and the insertion of its relative password is mandatory.
    Next you need to create a binding type object different from the usual one, while the endpoint object will remain on the same type:

    var Binding = new WSHttpBinding();
    Binding.Security.Mode = SecurityMode.Transport;
    Binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
    EndpointAddress ServiceEndPoint = new EndpointAddress(https://EndpointAddress.com);

    Note: This time the endpoint is on HTTPS, no longer on HTTP, indeed this type of binding is compatible only with https.

    Then you need to create the client object and set the certificate on it:

    ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
    ServiceReference.ServiceResult result = client.Method(ServiceParameter);
    
    Client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new System.ServiceModel.Security.X509ServiceCertificateAuthentication();
    System.ServiceModel.Security.X509CertificateInitiatorClientCredential certificateInitiator = 
    Client.ClientCredentials.ClientCertificate;
    certificateInitiator.Certificate = certificate;

    With this we have set up communication through the certified channel, now we must make sure that a token at our convenience is also included in the header of the generated HTTPS request. This is quite complicated, to be able to do it you need to act on the context of the call:

    using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
    {
           MessageHeader<string> header = new MessageHeader<string>("Bearer " + Oautoken);
           var untyped = header.GetUntypedHeader("Authorization", "");
           OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
           HttpRequestMessageProperty requestMessage = new 
           HttpRequestMessageProperty();
           requestMessage.Headers["Authorization"] = "Bearer " + "TokenString";          
           OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] 
           = requestMessage;
           result = client.method(serviceParameter);
    }


  • Come chiamare un Web service tramite certificato Client e autenticazione Oauth2 tramite libreria c#

    English version.
    Chi è già del mestiere , sa che Visual studio viene in aiuto degli sviluppatori che devono eseguire chiamata a servizi web, fornendo a questi, delle librerie generate analizzando il file WSDL del servizio.

    Ma quando la chiamata deve avvenire attraverso un canale cifrato, con un certificato client, ed in più il server si attende un token di autenticazione Oauth2 incluso nella richiesta, il lavoro si complica.

    Con C# è abbastanza semplice effettuare un richiesta HTTP utilizzando un certificato client per effettuare la chiamata, sulla stessa richiesta HTTP è semplice anche aggiungere il token OAuth2 fra gli Header.
    Se la richiesta è semplice (Ha pochi parametri e non strutturati su più livelli), lo sviluppatore può inviare una richiesta HTTP grezza, inserendo i parametri nel body di questa.
    Se invece i parametri della richiesta sono molti e molto strutturati , fare una cosa del genere, porterebbe via moltissimo tempo.

    Io ho trovato il modo di utilizzare le librerie generate da Visual studio , su un canale criptato e con il token di autenticazione Oauth2.

    Qui di seguito il codice che si userebbe per una chiamata con il metodo consueto:

    var Binding = new BasicHttpBinding();
    EndpointAddress ServiceEndPoint = new EndpointAddress("http://EndpointAddress.com");
    ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
    ServiceReference.ServiceResult result = client.Method(ServiceParameter);

    Volendo invece effettuare la chiamata su canale cifrato, occorre prima creare un oggetto certificate:

    X509Certificate2 certificate = new X509Certificate2("filePath.p12", "Password");

    Dove il file contenente il certificato deve essere in formato p12 e l’inserimento della sua relativa password è obbligatorio.
    Successivamente bisogna creare un oggetto di tipo binding diverso dal consueto, mentre l’oggetto endpoint rimarrà dello stesso tipo:

    var Binding = new WSHttpBinding();
    Binding.Security.Mode = SecurityMode.Transport;
    Binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
    EndpointAddress ServiceEndPoint = new EndpointAddress(https://EndpointAddress.com);

    Nota bene: L’endpoint questa volta è su HTTPS , non più su HTTP, infatti questo tipo di binding è compatibile sono con https.

    Poi è necessario creare l’oggetto client e impostarvi sopra il certificato:

    ServiceReference.Serviceclient client = new ServiceReference.Serviceclient(Binding, ServiceEndPoint);
    ServiceReference.ServiceResult result = client.Method(ServiceParameter);
    
    Client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new System.ServiceModel.Security.X509ServiceCertificateAuthentication();
    System.ServiceModel.Security.X509CertificateInitiatorClientCredential certificateInitiator = 
    Client.ClientCredentials.ClientCertificate;
    certificateInitiator.Certificate = certificate;

    Con questo abbiamo impostato la comunicazione attraverso il canale certificato, adesso dobbiamo fare in modo che nell’header della richiesta HTTPS generata, venga incluso anche un token a nostro piacimento.
    Questo è abbastanza complicato, per poterlo fare bisogna agire sul contesto della chiamata:

    using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
    {
           MessageHeader<string> header = new MessageHeader<string>("Bearer " + Oautoken);
           var untyped = header.GetUntypedHeader("Authorization", "");
           OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
           HttpRequestMessageProperty requestMessage = new 
           HttpRequestMessageProperty();
           requestMessage.Headers["Authorization"] = "Bearer " + "TokenString";          
           OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] 
           = requestMessage;
           result = client.method(serviceParameter);
    }