Wednesday, 29 October 2014

wcf rest service authentication by username password

Securing WCF with Forms Authentication

In this post i will explain how to secure Rest ful Service without SSL Certificate, i just apply form authentication in these. first and new WCF Service Application in VS 2010.
 
Create new service ILoginService like these-
 [ServiceContract]
    public interface ILoginService
    {
        [OperationContract]
        bool Login(string userName, string password);
    }
 Now i am using entity framework for authenticate user that's way i have added one edmx file like these-
 in that database i have two tables one is UserTable and another is tblEmployee.
      
Now i need to implemented method in Loginservice like these-
In these page i validate user with the help of entity framework method and create AuthTicket with user information and after that we encrypt the user information and add to cookie.  

 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,IncludeExceptionDetailInFaults=true)] 
    public class LoginService : ILoginService
    {
        TestEntities db = new TestEntities(); //Edmx context reffrence
        public bool Login(string userName, string password)
        {
            bool returnValue = false;
            UserTable user;
            using (var ctx = new TestEntities())
            {
                user = ctx.UserTables.Where(one => one.UserName == userName).FirstOrDefault();
                if (user != null)
                {
                    returnValue = (user.Password == password);
                }
            }
            if (returnValue)
            {
             //Create  Authentic ticket for user
                var AutTicket = new FormsAuthenticationTicket(
                        1,
                        userName,
                        DateTime.Now,
                        DateTime.Now.AddDays(1),
                        true,
                        user.Id.ToString()
                    );
             // Encrypt user detail
                string encryptedTicket = FormsAuthentication.Encrypt(
AutTicket);
                var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            // Add Encrypt detail in to cookie.
                HttpContext.Current.Response.Cookies.Add(cookie);
            }
            return returnValue;
        }
    }
 Now add one class RestService.cs for define method for Restful Service like these -
//Return string 
 [WebGet(UriTemplate = "/GetTest", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public string GetTest()
        {
            return "test";
      }
//Return XElement
[WebInvoke(Method = "POST", UriTemplate = "/CaptureTest", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        public XElement CaptureTest(XElement x)
        {
            // For get the encrypted value from request
            string testcookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value;
          
             //Now Decrypt  the cookie and get the user detail        
             FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(testcookie);
          
            return XElement.Parse("<Result>xml captured</Result>");
        } 
Now in WCFRestService web.config file-
<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="TestEntities" connectionString="metadata=res://*/WCFModel.csdl|res://*/WCFModel.ssdl|res://*/WCFModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.;Initial Catalog=Test;User ID=sa;Password=server;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
    <authentication mode="Forms">
    </authentication>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
  <location path="LoginService.svc">
    <system.web>
      <authorization>
        <allow users="?" />
      </authorization>
    </system.web>
  </location>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" />
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>
</configuration>
 
RestFulService work is end here.now i want to consume that service in my WebApplication.
Add New  website then Add Service Reference in that application now in one webpage i have tried to access that service i have write that code on page-load event for test-

protected void Page_Load(object sender, EventArgs e)
        {
 var Cookie = string.Empty;
            bool isValid;
            string data = string.Empty;

            var userAuth= new LoginServiceClient(); //that comes from service refrence
            using (new OperationContextScope(authClient.InnerChannel))
            {
                isValid =
userAuth.Login("username", "password");
                if (isValid)
                {
                    var response = (HttpResponseMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
                    Cookie = response.Headers["Set-Cookie"];
                }
              if (isValid)
            {
                // For Capture Test check
                var request = (HttpWebRequest)WebRequest.Create("http://localhost:48090/
RestService/CaptureTest");
                request.Timeout = 30000;
                request.Method = "POST";
                request.ContentType = "text/xml";
                request.Headers["Cookie"] =
Cookie;

                var xmlDoc = new XmlDocument { XmlResolver = null };
                xmlDoc.Load(Server.MapPath("PostData.xml"));
                string sXml = xmlDoc.InnerXml;
                request.ContentLength = sXml.Length;
                var sw = new StreamWriter(request.GetRequestStream());
                sw.Write(sXml);
                sw.Close();

                HttpWebResponse res = null;
                var tst = request.GetResponse();
                res = (HttpWebResponse)request.GetResponse();
                Stream responseStream = res.GetResponseStream();
                var streamReader = new StreamReader(responseStream);
                string str = string.Empty;
                str = streamReader.ReadToEnd();
              //End Capture Test
               
             // For GetTest Method 
              
               var request2 = (HttpWebRequest)WebRequest.Create("http://localhost:48090/RestService/GetTest");
                request2.Headers["Cookie"] = Cookie;
               var responce2 = request2.GetResponse();
                using (var stream = responce.GetResponseStream())
                {
                    using (var reader = new StreamReader(stream))
                    {
                        data = reader.ReadToEnd();
                        Console.Write(data);
                    }
                }
            }