Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Thursday, 30 May 2013

WCF Security

few reads for my reference

Securing services
Authentication, Authorization, and Identities in WCF
Federated Security

Message Security with Certificates for Client/Server validation

few reads

http://msdn.microsoft.com/en-us/library/ms733098.aspx
http://msdn.microsoft.com/en-us/library/ms751516.aspx
http://stackoverflow.com/questions/1570939/wcf-message-security-without-certificate-and-windows-auth

and create two certificates - for client/server.

Server

ICalculator.cs
using System.ServiceModel;
 
namespace MySimpleCalculator
{
    [ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        int Add(int num1, int num2);
 
        [OperationContract]
        string GetCallerIdentity();
    }
}

Calculator.svc
<%@ ServiceHost Language="C#" Debug="true" Service="MySimpleCalculator.Calculator" CodeBehind="Calculator.svc.cs" %>
Calculator.svc.cs

using System.ServiceModel;
namespace MySimpleCalculator
{
    public class Calculator : ICalculator
    {
        public int Add(int num1, int num2)
        {
            return num1 + num2;
        }
 
        public string GetCallerIdentity()
        {
            // The client certificate is not mapped to a Windows identity by default.
            // ServiceSecurityContext.PrimaryIdentity is populated based on the information
            // in the certificate that the client used to authenticate itself to the service.
            return ServiceSecurityContext.Current.PrimaryIdentity.Name;
        }
    }
}
 
web.config 

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceCredentialsBehavior">
          <serviceCredentials>
            <serviceCertificate findValue="CN=Server" 
                 x509FindType="FindBySubjectDistinguishedName"/>
            <clientCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust" 
                    revocationMode="NoCheck" />
            </clientCertificate>
          </serviceCredentials>
          <!-- 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="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="MySimpleCalculator.Calculator" behaviorConfiguration="ServiceCredentialsBehavior">
        <endpoint contract="MySimpleCalculator.ICalculator" address="/SimpleCalculator" 
                  binding="wsHttpBinding"
                  bindingConfiguration="MessageUsingCertificate" />
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="MessageUsingCertificate">
          <security mode="Message">
            <message clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  
</configuration>
------------------------------------------------------------------------

client

class Program
{
   static void Main(string[] args)
   {
      ServiceReference1.CalculatorClient client = new ServiceReference1.CalculatorClient();
 
      Console.WriteLine(client.Add(1, 2));
      Console.WriteLine(client.GetCallerIdentity());
 
      Console.ReadLine();
    }
}
 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ICalculator">
                    <security>
                        <message clientCredentialType="Certificate" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
      <behaviors>
        <endpointBehaviors>
          <behavior name="endpointCredentialsBehavior">
            <clientCredentials>
              <clientCertificate findValue="CN=client"
                 storeLocation="LocalMachine"
                x509FindType="FindBySubjectDistinguishedName" />
              <serviceCertificate>
                <authentication revocationMode="NoCheck"/>
              </serviceCertificate>
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>
        <client>
            <endpoint address="http://localhost:18499/Calculator.svc/SimpleCalculator"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator"
                contract="ServiceReference1.ICalculator" name="WSHttpBinding_ICalculator"
                behaviorConfiguration="endpointCredentialsBehavior">
                <identity>
                    <certificate encodedValue="server certificate value" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration> 


Issues

1. {"The request for security token could not be satisfied because authentication failed."} - It means
   Server tries to authenticate Client certificate and its revocation status. So add 'No Revocation'
   @ server side for client certificate.
 
2. SOAP security negotiation with "uri" fails.

   The X.509 certificate CN=subject chain building failed. The certificate that was used has 
   a trust chain that cannot be verified. Replace the certificate or change the 
   certificateValidationMode. The revocation function was unable to check revocation for 
   the certificate. - This happens if server certificate is not trusted by client, add no revocation.
 
     

Tuesday, 26 February 2013

WCF serviceAuthorizationManager

ServiceAuthorizationManager can be used as custom authentication mechanism for WCF operations. So we can configure this in behavior tag

<behavior name="Behavior">
      <serviceAuthorization serviceAuthorizationManagerType="ClassThatImplementsServiceAuthorizationManager, Assembly" />
</behavior>

This is can code thru code like below

host = new WebServiceHost(typeof(Rest), address.Uri);
host.Authorization.ServiceAuthorizationManager=ClassThatImplementsServiceAuthorizationManager;

WCF Restful service with BASIC Authentication

Just wanted to show code for configuring BASIC authentication on REST service.

Hosting part
---------------
               WebHttpBinding binding = new WebHttpBinding();
                binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
                binding.Security.Transport.Realm = "domain"; //Enter domain name

                host = new WebServiceHost(typeof(Service), address.Uri);
                host.AddServiceEndpoint(typeof(IService), binding, address.Uri);
                host.Open();

Client
--------
           WebHttpBinding binding = new WebHttpBinding();

            binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
           
            using (WebChannelFactory factory = new WebChannelFactory(binding, address.Uri))
            {
                factory.Credentials.UserName.UserName = "user";
                factory.Credentials.UserName.Password = "password";

                var channel = factory.CreateChannel();

                channel.CallSomething();
            }

Thursday, 21 June 2012

IRequestChannel - Demo 1

Let's assume below ServiceContract

[ServiceContract]
public interface IDemo1
{
    [OperationContract]
    string HelloWorld(string name);
}

so how can we invoke above using IRequestChannel

var httpsBasicBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
var endpoint = "https://host/service.svc";
var channelFactory = new ChannelFactory<IRequestChannel>(httpsBasicBinding, endpoint);
var channel = null;
 
try
{
    channelFactory.Open();
 
    channel = channelFactory.CreateChannel();
 
    channel.Open(); 
    
    string body = "<HelloWorld xmlns="http://tempuri.org/"><name>Suresh</name></HelloWorld>";
    var messageBody = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(body)
    Message message = Message.CreateMessage(MessageVersion.Soap11,  
                       "http://tempuri.org/IDemo1/HelloWorld");
 
    Message response = channel.Request(message);
    var result = response.GetReaderAtBodyContents().ReadOuterXml(); //parse based on the requirments
    
    Console.WriteLine(result);
    
    channel.Close();
}
finally
{
    channel.close(); //abort if faulted 
    channelFactory.Close(); //abort if faulted
}
 
reference : http://www.codeproject.com/Articles/34632/How-to-pass-arbitrary-data-in-a-Message-object-usi 

Monday, 23 April 2012

HTTP 500.0 - Internal Server Error in Windows 2008 R2 Server

After deploying a 32-Bit WCF service in IIS 7.5(Windows 2008 R2 server), browsing the service failed with
HTTP 500.0 - Internal Server Error, and from the error message i figured out something wrong with PageHandlerFactory. For 32-Bit web apps, it is mandatory to set 'Enable 32-Bit Applications' to 'True'. We can either set it @ 'Application Pool Defaults' or the specific Application Pool in question.

Wednesday, 4 January 2012

Console client for a WCF Restful service protected with BASIC authentication(windows credential)

Please refer my earlier post for REST service details, below is an sample code to pass on windows credentials while calling WCF REST service(in IIS - Anonymous access is disabled and BASIC is enabled)

static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/SimpleService");

            try
            {
                WebHttpBinding binding = new WebHttpBinding();

                binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

                WebChannelFactory cf = new WebChannelFactory(binding, baseAddress);
       
                //If Default domain is not added in IIS, provide it below - else not needed
                cf.Credentials.UserName.UserName = "user";
                cf.Credentials.UserName.Password = "password";

                SimpleInterface channel = cf.CreateChannel();
               
                Console.WriteLine("Reply Hi : {0}", channel.ReplyHi("Hello, world"));
                Console.WriteLine("Reply Hii : {0}",channel.ReplyHii("Hello, world"));
             }
            catch (CommunicationException ex)
            {
                Console.WriteLine("An exception occurred: " + ex.Message);
            }
        }

WCF Absolute Vs Relative address

After long break, i started working on WCF services and i struck with a problem when i hosted my service in IIS. I figured out that i have given an absolute end point address, which is wrong. So i figured out below in MSDN

'When hosting with IIS, you do not manage the ServiceHost instance yourself. The base address is always the address specified in the .svc file for the service when hosting in IIS. So you must use relative endpoint addresses for IIS-hosted service endpoints. Supplying a fully-qualified endpoint address can lead to errors in the deployment of the service. For more information, see Deploying an Internet Information Services-Hosted WCF Service."

So with following config
       
<services>
   <service name="RestService.SimpleService">
        <endpoint address="/Sample" binding="webHttpBinding"
                  contract="RestService.SimpleInterface" behaviorConfiguration="webby"
                   bindingConfiguration="secure"/>
     </service>
</services>

i hosted my WCF(REST) as 'SimpleRestService' application, so i need to use http://localhost/SimpleRestService/yoursvcfilename.svc/Sample/youroperationname

Issues while hosting Restful WCF services in IIS

When i hosted my Hello World WCF Restful services, i faced below issue

The requested content appears to be script and will not be served by the static file handler.

My application is using 'DefaultAppPool', For reasons unknown to me, running the below did work. 

c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i

But soon after this i ran into below issue

"Could not load type 'System.ServiceModel.Activation.HttpModule'"

For reasons unknown to me, running the below did work :(.   

c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /iru

http://forums.asp.net/t/1432329.aspx/1 

http://www.fredmastro.com/post/HTTP-Error-40417-Not-Found-e28093-Using-WCF-SVC-Service.aspx 

http://support.microsoft.com/kb/2015129

Tuesday, 3 January 2012

Restful WCF services hosted in Console Application

Sorry - No descriptions, i am bored to death, hence only the code.

 namespace SimpleConsoleWCFHost
{
    [ServiceContract]
    public interface SimpleInterface
    {
        ///

        /// POST, bare body message - http://localhost:8080/SimpleService/SayHi/Suresh
        /// Content-Type: text/html
        ///

        ///
        [OperationContract]
        [WebInvoke(Method="POST", BodyStyle = WebMessageBodyStyle.Bare,
                UriTemplate="SayHi/{name}")]
        void SayHi(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyHi/Suresh
        /// Content-Type: text/html
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare,
                UriTemplate = "ReplyHi/{name}")]
        string ReplyHi(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyHii?name=Suresh
        /// Content-Type: text/html
        ///

        ///
        ///
        [OperationContract]
        [WebGet]
        string ReplyHii(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyByJson?name=Suresh
        /// Content-Type: text/json
        ///

        ///
        ///
        [OperationContract]
        [WebGet(ResponseFormat=WebMessageFormat.Json)]
        SimpleData ReplyByJson(string name);

        ///
        /// GET, http://localhost:8080/SimpleService/ReplyByXml?name=Suresh
        /// Content-Type: application/xml
        ///

        ///
        ///
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Xml)]
        SimpleData ReplyByXml(string name);

        ///
        /// POST, http://localhost:8080/SimpleService/ConverseUsingJson
        /// Content-Type: text/json
        /// {"Body":"Comment received at 03-01-2012 10:13:55","Header":"Welcome to JSON - Suresh"}
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(UriTemplate = "ConverseUsingJson", Method = "POST",
            RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        SimpleData ConverseUsingJson(SimpleData data);

        ///
        /// POST, http://localhost:8080/SimpleService/ConverseUsingXml
        /// Content-Type: application/xml
        /// colin
        /// http://www.britishdeveloper.co.uk/2011/01/how-to-post-rest-fiddler.html
        ///

        ///
        ///
        [OperationContract]
        [WebInvoke(UriTemplate = "ConverseUsingXml", Method = "POST",
            RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        SimpleData ConverseUsingXml(SimpleData data);
    }

    [DataContract(Namespace = "")]
    public class SimpleData
    {
        [DataMember]
        public string Header { get; set; }

        [DataMember]
        public string Body { get; set; }
    }

    public class SimpleService : SimpleInterface
    {
        public void SayHi(string name)
        {
            Console.WriteLine("Hi " + name);
        }

        public string ReplyHi(string name)
        {
            return "Hi " + name;
        }

        public string ReplyHii(string name)
        {
            return "Hii " + name;
        }

        public SimpleData ReplyByJson(string name)
        {
            return new SimpleData
            {
                Header = "Welcome to JSON - " + name,
                Body = "Comment received at " + DateTime.UtcNow.ToString()
            };
        }

        public SimpleData ReplyByXml(string name)
        {
            return new SimpleData
            {
                Header = "Welcome to XML - " + name,
                Body = "Comment received at " + DateTime.UtcNow.ToString()
            };
        }

        public SimpleData ConverseUsingJson(SimpleData value)
        {
            value.Header = "JSON Conversation";

            return value;
        }

        public SimpleData ConverseUsingXml(SimpleData value)
        {
            value.Header = "XML Conversation";

            return value;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/");
            string serviceName = "SimpleService";

            using (WebServiceHost webHost = new WebServiceHost(typeof(SimpleService), baseAddress))
            {
                ServiceEndpoint sp = webHost.AddServiceEndpoint(typeof(SimpleInterface), new WebHttpBinding(), serviceName);
                //ServiceDebugBehavior sdb = webHost.Description.Behaviors.Find();
                //sdb.HttpHelpPageEnabled = false;

                webHost.Open();

                Console.WriteLine("Host Opened");
                Console.ReadLine();

                webHost.Close();

                Console.WriteLine("Host Closed");
            }
        }
    }
}


Some fiddler shots below