An Unsecured or Incorrectly Secured Fault Was Received From The Other Party

an-unsecured-or-incorrectly-secured-fault-was-received-from-the-other-party

The inner FaultException goes something like: System.ServiceModel.FaultException: The message could not be processed because the action ‘http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/SCT’ is invalid or unrecognized.

It’s caused by WCF service configured to not communicate in WS-SecureConversation while the client is. Or vice versa. In my case, the client is an ASP.NET MVC 4 application that is trying to pass token (identity delegation) over to a WCF 4.5 service through WSTrustChannelFactory protocol.

Both of the client and the service must be configured to use same security context. If you want to turn WS-SecureConversation off, turn off on both config. Same applies to turning on WS-SecureConversation.

<ws2007FederationHttpBinding>
    <binding>
        <security mode="TransportWithMessageCredential">
            <message establishSecurityContext="false" />
        </security>
    </binding>
</ws2007FederationHttpBinding>

WCF Client Config Template with Identity Delegation (WSTrust)

A minimal config for a client (for example, ASP.NET MVC application, ASP.NET Web Form application, or another WCF service application), that is a relying party to WIF (or any STS), to consume a WCF service (SOAP) using Identity Delegation (with WSTrust protocol). Identity Delegation allows the client to call WCF service and pass in the claims as if it’s being called by the user of the client. Compare Identity Delegation to Trusted Subsystem.

This config is auto-generated with “Add Service Reference” wizard from WCF service config in WCF Config Template for Identity Delegation with WIF.

This config DOES NOT include setting integrating the client with WIF. For example of this, see WIF 3.5 Relying Party Config Template.

Note that:
http://localhost:11000 is the Secure Token Service (STS) URL.
http://localhost:58829 is service’s endpoint address.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <ws2007FederationHttpBinding>
                <binding name="WS2007FederationHttpBinding_IService">
                    <security>
                        <message>
                            <issuer address="http://localhost:11000/Issue.svc" binding="ws2007HttpBinding"
                                bindingConfiguration="http://localhost:11000/Issue.svc">
                                <identity>
                                    <dns value="IdentityTKStsCert" />
                                </identity>
                            </issuer>
                            <issuerMetadata address="http://localhost:11000/Issue.svc/mex" />
                            <tokenRequestParameters>
                                <trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
                                    <trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
                                    <trust:KeySize xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">256</trust:KeySize>
                                    <trust:KeyWrapAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
                                    <trust:EncryptWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
                                    <trust:SignWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
                                    <trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
                                    <trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
                                </trust:SecondaryParameters>
                            </tokenRequestParameters>
                        </message>
                    </security>
                </binding>
            </ws2007FederationHttpBinding>
            <ws2007HttpBinding>
                <binding name="http://localhost:11000/Issue.svc">
                    <security>
                        <message clientCredentialType="Certificate" negotiateServiceCredential="false" />
                    </security>
                </binding>
            </ws2007HttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:58829/Service.svc" binding="ws2007FederationHttpBinding"
                bindingConfiguration="WS2007FederationHttpBinding_IService"
                contract="ServiceReference.IService" name="WS2007FederationHttpBinding_IService">
                <identity>
                    <certificate encodedValue="AwAAAAEAAAAUAAAAQKHSYiv" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

To create ChannelFactory and pass in the secured token from the client:

// Get the token
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory( stsBinding, stsAddress );
WSTrustChannel channel = (WSTrustChannel) trustChannelFactory.CreateChannel();
RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue);
rst.AppliesTo = new EndpointAddress(serviceAddress);
RequestSecurityTokenResponse rstr = null;
SecurityToken token = channel.Issue(rst, out rstr);

// Use the token, pass in to WCF service
IHelloService serviceChannel = channelFactory.CreateChannelWithIssuedToken<IHelloService>( token ); serviceChannel.Hello(“Hi!”);

Additional resource: MSDN WSTrustChannelFactory and WSTrustChannel

WCF Config Template for Identity Delegation with WIF 3.5

A minimal config for WCF (.Net 4.5) service. The binding allows Identity Delegation with WIF 3.5. For WIF 4.5, use Identity and Access Tool.

The config template includes WIF configuration. It’s necessary because the WCF service, in this case, is a relying party.

Note that:
http://localhost:11000 is the Secure Token Service (STS) URL.
http://localhost:58829 is service’s endpoint address (the relying party).

The downside with this is that you can’t invoke the service with WCF Test Client. It will complain about “SOAP security negotiation failed.” with inner exception “Client certificate is not provided”. This is because WCF Test Client is not configured with SOAP security negotiation (maybe there’s a way?).

<?xml version="1.0"?>
<configuration>
    <configSections>

        <!--For WIF 3.5-->
        <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    </configSections>

    <system.web>
        <compilation debug="true" targetFramework="4.5" />
    </system.web>

    <system.serviceModel>
        <bindings>

            <!--For Identity Delegation-->
            <ws2007FederationHttpBinding>
                <binding name="ws2007FederationHttpBinding_IService">
                    <security mode="Message">
                    <!--TransportWithMessageCredential requires HTTPS-->
                    <!--<security mode="TransportWithMessageCredential">-->
                        <message>
                            <issuerMetadata address="http://localhost:11000/Issue.svc/mex" />
                        </message>
                    </security>
                </binding>
            </ws2007FederationHttpBinding>

        </bindings>

        <services>

            <!--For Identity Delegation-->
            <service name="Acme.AccountService.Service" behaviorConfiguration="AcmeService.Service_Behavior">
                <endpoint binding="ws2007FederationHttpBinding" bindingConfiguration="ws2007FederationHttpBinding_IService" contract="Acme.AccountService.Contracts.IService" />
            </service>

        </services>

        <behaviors>
            <serviceBehaviors>

                <!--For Identity Delegation-->
                <behavior name="AcmeService.Service_Behavior">
                    <federatedServiceHostConfiguration />
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceCredentials>
                        <serviceCertificate findValue="40A1D2622BFBDAC80A38858AD8001E09454987AD" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
                    </serviceCredentials>
                    <serviceAuthorization principalPermissionMode="Always" />
                </behavior>

            </serviceBehaviors>
        </behaviors>

        <!--For Identity Delegation-->
        <extensions>
            <behaviorExtensions>
                <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            </behaviorExtensions>
        </extensions>

        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>

    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
    </system.webServer>

    <!--For WIF 3.5-->
    <microsoft.identityModel>
        <service saveBootstrapTokens="true">
            <audienceUris>
                <add value="http://localhost:58829/" />
            </audienceUris>

            <federatedAuthentication>
                <wsFederation passiveRedirectEnabled="true" issuer="http://localhost:11000/Issue.svc" realm="http://localhost:58829/" requireHttps="false"/>
                <cookieHandler requireSsl="false"/>
            </federatedAuthentication>

            <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
                <trustedIssuers>
                    <add thumbprint="40A1D2622BFBDAC80A38858AD8001E09454987AD" name="http://localhost:11000/Issue.svc"/>
                </trustedIssuers>
            </issuerNameRegistry>
        </service>
    </microsoft.identityModel>
</configuration>

WCF Client Config Template (w/ wsHttpBinding)

This applies to WCF in .Net 4.5. This is a minimum config used for WCF SOAP client. It is auto-generated using “Add Service Reference” wizard from WCF service config in SOAP WCF Config Template (w/ wsHttpBinding).

http://localhost:58829 is the service’s endpoint address.

<?xml version="1.0"?>
<configuration>
  <!--For WCF-->
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IService">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <!--'address' refers to the service's endpoint address-->
      <endpoint address="http://localhost:58829/Service.svc" binding="wsHttpBinding"
          bindingConfiguration="WSHttpBinding_IService" contract="ServiceReference.IService"
          name="WSHttpBinding_IService" />
    </client>
  </system.serviceModel>
</configuration>

SOAP WCF Config Template (w/ wsHttpBinding)

A minimum config settings for WCF (.Net 4.5) with wsHttpBinding and no security.

<?xml version="1.0"?>
  <configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
    </system.web>
    <system.serviceModel>
      <bindings>
        <wsHttpBinding>
          <binding name="wsHttpBinding_IService">
            <security mode="None" />
          </binding>
        </wsHttpBinding>
      </bindings>
      <services>
        <service name="Acme.SOA.JunoService.Service">
          <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_IService" contract="Acme.SOA.JunoService.Contracts.IService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

Differences Between WCF and Web API

There are good reasons to use ASP.Net Web API instead of WCF. But, what are the differences?

WCF Web API
Support SOAP and REST. Support only REST.
Protocols supported: TCP, HTTP, HTTPS, Named Pipes, MSMQ. Only HTTP / HTTPS protocols are supported. It uses full-feature of HTTP (URIs, request / response headers, caching, content formate, etc)
Data formats supported: XML, JSON, ATOM. Data formats supported are typically JSON and XML. But can be extended with Web API’s MediaTypeFormatter.
Required extensive configurations. Very little configurations. Development is similar to coding in ASP.Net MVC.
Passing parameters to WCF operations need configurations and must be specified in UriTemplate. Parameters are bound automatically, similar to ASP.Net MVC Model Binding feature.
Web API’s URI is by convention (controller / action name).
HTTP verbs supported: GET, POST. Other verbs are supported with more IIS configurations. Support full HTTP verbs. GET, POST, PUT, DELETE, PATCH, HEAD, etc.
Can be hosted on IIS, Windows Service, or with in a web application. Can be hosted on IIS or with in a web application.
WCF is bigger framework, allowing full customization, such as SOAP, REST or WS-*. To support MVC features, it requires heavy customization and configuration. Supports the MVC features such as routing, controllers, action results, filter, model binders, IOC container or dependency injection, unit testing.

More reading about Web Service, WCF, WCF REST, Web API.

Why ASP.Net Web API and Not WCF?

Excerpt from Ido Flatow

  • Even with WCF REST starter kit (or new features in WCF 4), we didn’t get any of the client-side libraries.
  • Although we did get most of the service-side features, the new inspectors feature is not included.
  • Although some of the service-side features were well-integrated into WCF, others required the use of ASP.NET by turning on the ASP.NET compatibility mode.
  • To get some of the new features in WCF 4, you needed IIS hosting and ASP.NET.
  • Not all types of requests were supported easily (ever tried posting HTML form data to a WCF HTTP service?).
  • Overuse of CLR attributes to define the POST/GET/PUT/DELETE was tedious.
  • Configuration required to create “Web” HTTP (RESTful) type of services with all of the endpoint behavior.
  • WCF is heavy in configurations.
  • WCF overuses attributes.
  • WCF infrastructure did not support testing well.

Service Oriented Architecture (SOA) Benefits

Many need justification to go with service oriented architecture. Below are just few SOA benefits, both business and technical:

  • Reducing integration expense
    Integration point could be time-consuming and expensive because of its maintenance. By building SOA and allowing others to access your services, you will shift integration to client’s side, omitting the needs for you to maintenance integration for your clients. Your clients, in return, has benefits of customizing integration point to their needs. Win-win situation.
  • Reducing hardware cost
    Because the nature of SOA is ad-hoc calls, which means services are called on-demand, it will consume resources only when necessary. This essentially reduce hardware costs.
  • Data exposure
    Data exposure could be good way if managed properly. Many companies have succeed through exposing their data. Case and point, Amazon.com and Facebook. By exposing and allowing others to use your data, you are creating dependency toward your platform. This basically means you can’t fail, because when you fail, others will follow in which it leads others to support your business nature.
  • One central source
    SOA when build properly could be one central source of all your data. This reduce needs of going different places to gather data because SOA is handling that and providing in the form of services for you. One central source is always good for it will save your time almost instantly.
  • Cross platform
    SOA doesn’t need specific platform to call, it’s cross-platform. Because SOA is built on top of today’s Internet standard, all platforms are allowed to access using these standards. No need to reinvent the wheel and one can focus on developing business model.

OData System Query Options

OData system queries are:

Source: OData

File Upload Service x Base64 x Byte[] x All in C#

It’s SOA age and I am going to post on how to create File Upload service to be used in SOA design. This is only a basic concept and NOT a step-by-step, very-detail-cliff-note type of guidance.

Normally, to allow file upload in a form, you would include the following enctype in your <form>

enctype="multipart/form-data" runat="server"

This is a traditional web form uploader. More on this later. In SOA, we don’t need this. Well, obviously… because it’s SOA! And because of that too, it’s much simpler than web form. All we need are:

  1. A service (REST or SOAP) that will take HTTP POST data.
    The service will take HTTP POST data, parse it out and pass it to Conversion class. The POST is basically a Base64 string of uploaded file. That being said, to invoke this service, service consumers will need to convert files to Base64 string. Then when invoking the service, the Base64 string is passed on POST data.
  2. Conversion class to convert Base64 to Byte[] and from Byte[] to Stream (File or Memory).
    Conversion class is just a class to convert from Stream > Byte[] > Base64 and other way around.

.Net framework already has static method to convert Byte[] to Base64:

Convert.ToBase64String();
Convert.FromBase64String();

Remember, the order of conversion is:

Stream > Byte[] > Base64

Whether you are converting from file to Base64 or vice versa, you will first have to convert to Byte[]. As for the Stream, this can be System.IO.FileStream (for file) or any other Stream such as System.IO.MemoryStream.

Here’s my conversion class look like:

/// <summary>
/// Convert given file to Base64 string.
/// </summary>
/// <param name="filename">Full path of the file to be converted. Ex: "C:\My Files\Kiba.jpg"</param>
/// <returns>string</returns>
public static string FileToBase64(string filename)
{
    return Convert.ToBase64String(FileToByteArray(filename));
}

/// <summary>
/// Convert given file to byte array.
/// </summary>
/// <param name="filename">Full path of the file to be converted. Ex: "C:\My Files\Kiba.jpg"</param>
/// <returns>byte[]</returns>
public static byte[] FileToByteArray(string filename)
{
    byte[] returnByteArray = null;
    // Instantiate FileStream to read file
    System.IO.FileStream readFileStream = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read);

    // Instantiate BinaryReader and attach FileStream with the object
    System.IO.BinaryReader readBinaryReader = new System.IO.BinaryReader(readFileStream);

    // Get file's byte length
    long fileByteSize = new System.IO.FileInfo(filename).Length;

    // Read bytes from the file
    returnByteArray = readBinaryReader.ReadBytes((Int32)fileByteSize);

    // Clean up / disposal
    readFileStream.Close();
    readFileStream.Dispose();
    readBinaryReader.Close();
    return returnByteArray;
}

/// <summary>
/// Convert given Base64 string to file based on given filename.
/// </summary>
/// <param name="base64String">String of Base64</param>
/// <param name="filename">Full path of the file to be converted. Ex: "C:\My Files\Kiba.jpg"</param>
public static void Base64ToFile(string base64String, string filename)
{
    byte[] fileByteArray = Convert.FromBase64String(base64String);
    // Instantiate FileStream to create a new file
    System.IO.FileStream writeFileStream = new System.IO.FileStream(filename, System.IO.FileMode.Create, System.IO.FileAccess.Write);
    // Write converted base64String to newly created file
    writeFileStream.Write(fileByteArray, 0, fileByteArray.Length);
    // Clean up / disposal
    writeFileStream.Close();
}

I will discus traditional web form upload on future post. Meantime, this link will be helpful: Web form file upload.