WINDOWS authentication on REST enabled WCF service
Enabling windows authentication on a REST enabled service is relatively easier task than it's appear. To test that windows authentication is enabled successfully or not use other browser than Internet explorer because
IE will automatically do an NTLM negotiation with domain credentials. So when REST service is running in IE, it is not prompting for user credentials.
Service
A very simple contract as REST service, I am going to use.
Contract
namespace RestserviceWindows { [ServiceContract] public interface IService1 {
[OperationContract] [WebGet()] string GetData();
}} |
Service implementation
namespace RestserviceWindows { public class Service1 : IService1 { public string GetData() { return "Testing Windows Authentication with REST service"; } }} |
Configuring the Service
Method #1 Using Factory class
a. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
b. WCF will create default endpoints inside System.ServiceModel. Delete both the default endpoints. Delete below end points.
<endpoint address="" binding="wsHttpBinding" contract="RestserviceWindows.IService1"> <identity> <dns value="localhost"/> identity> endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> |
c. Right click on .SVC file. If your service name is Service1 then right click on Service1.svc. After right clicking select
View Markup. Add Factory here
| <%@ ServiceHost Language="C#" Debug="true" Service="RestserviceWindows.Service1" CodeBehind="Service1.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %> |
d. Host the service in IIS. To host right click on service and Publish in IIS.
e. Configure IIS for windows authentication.
The above 5 steps are required to host a REST service in IIS with windows authentication.
Method #2 Configuring End Point without Meta Data
a. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
b. Delete endpoint address for
MEX and binding
mexHttpBinding c. Configure EndPoint to enable REST service.
d. Configure EndPoint to enable windows authentication on the service.
e. Configure End Point behavior.
f. Make sure, there is no factory class provided for the service in markup of .svc
| <%@ ServiceHost Language="C#" Debug="true" Service="RestserviceWindows.Service1" CodeBehind="Service1.svc.cs" %> |
g. Host the service in IIS. To host right click on service and Publish in IIS.
h. Configure IIS for windows authentication.
<system.serviceModel> <services> <service name="RestserviceWindows.Service1" behaviorConfiguration="RestserviceWindows.Service1Behavior"> <endpoint address="" binding="webHttpBinding" contract="RestserviceWindows.IService1" bindingConfiguration ="RESTBINDING" behaviorConfiguration ="REST"> <identity> <dns value="localhost"/> identity> endpoint> service> services> <behaviors> <serviceBehaviors> <behavior name="RestserviceWindows.Service1Behavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> behavior> serviceBehaviors> <endpointBehaviors> <behavior name ="REST"> <webHttp/> behavior> endpointBehaviors> behaviors> <bindings> <webHttpBinding> <binding name ="RESTBINDING"> <security mode ="TransportCredentialOnly"> <transport clientCredentialType ="Windows"/> security> binding> webHttpBinding> bindings> system.serviceModel> |
Method # 3 Configuring End Point with Meta Data
So far in above two methods, Meta Data is not getting exposed. Because
mexHttpBinding only supports anonymous binding. So to enable windows authentication on mexHttpBinding , we need to configure IMetaDataContract with some other binding like basicHttpBinding or webHttpBinding.
a. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
b. Configure EndPoint to enable REST service.
c. Configure EndPoint to enable windows authentication on the service.
d. Configure End Point behavior for both End Points.
e. Make sure, there is no factory class provided for the service in markup of .svc
| <%@ ServiceHost Language="C#" Debug="true" Service="RestserviceWindows.Service1" CodeBehind="Service1.svc.cs" %> |
f. Host the service in IIS. To host right click on service and Publish in IIS.
g. Configure IIS for windows authentication.
<system.serviceModel> <services> <service name="RestserviceWindows.Service1" behaviorConfiguration="RestserviceWindows.Service1Behavior"> <endpoint address="" binding="webHttpBinding" contract="RestserviceWindows.IService1" bindingConfiguration ="RESTBINDING" behaviorConfiguration ="REST"> <identity> <dns value="localhost"/> identity> endpoint> <endpoint address="mex" binding="webHttpBinding" contract="IMetadataExchange" bindingConfiguration ="RESTBINDING"/> service> services> <behaviors> <serviceBehaviors> <behavior name="RestserviceWindows.Service1Behavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> behavior> serviceBehaviors> <endpointBehaviors> <behavior name ="REST"> <webHttp/> behavior> endpointBehaviors> behaviors> <bindings> <webHttpBinding> <binding name ="RESTBINDING"> <security mode ="TransportCredentialOnly"> <transport clientCredentialType ="Windows"/> security> binding> webHttpBinding> bindings> system.serviceModel> |
Note: Binding for IMetaDataExchange contract is webHttpBinding.
Consuming the Service To enable a client to consume a windows authenticated WCF service, client has to pass domain credentials . If HttpClient is used by the client to consume the service then client has to set the credential like
clt.TransportSettings.Credentials=System.Net.CredentialCache.DefaultCredentials;where
clt is instance of HttpClient .a. Add Microsoft.Http and System.RunTime.Serlization assembly at refernece
b. Add namespace of Microsoft.Http and System.Runtime.Serlization
c. Create insatnce of HttpClint
d. Set the default credential from the cache.
e. Perfrom HTTP operation.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Http; using System.Runtime.Serialization; using System.Net; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string url = "http://localhost/RESTTESTING/Service1.svc/GetData"; HttpClient clt = new HttpClient(); clt.TransportSettings.Credentials = System.Net.CredentialCache.DefaultCredentials; HttpResponseMessage msg = clt.Get(url); string str = msg.Content.ReadAsDataContract<string>(); Console.WriteLine(str); Console.Read();
} } }
|