OpenLightGroup Blog

rss

Blogs from OpenLightGroup.net


Simple Example To Secure WCF Data Service OData Methods

Live Example: http://silverlight.adefwebserver.com/ODataAuthenticationSample/

So you want to use OData but you need to secure the data? There are a ton of ways to do this, but this covers a simple way using ASP.NET Forms Authentication.

This is a follow-up to the previous Blog (http://openlightgroup.net/Blog/tabid/58/EntryId/99/Simple-Silverlight-4-Example-Using-oData-and-RX-Extensions.aspx) where we looked a simple Silverlight application that talks to an oData service.

As with the last tutorial, we will not use a database, just a simple collection that we are creating programmatically. This will allow you to see just the oData parts.

 

ASP.NET Forms Authentication

Eventually I will create a few DotNetNuke Silverlight modules that will use OData. DotNetNuke uses ASP.NET Forms Authentication. Actually, every web application I have ever created uses ASP.NET Forms Authentication. My desire was to create a sample that uses the authentication that is created when the user logs into a website that uses ASP.NET Forms Authentication.

When a user logs into a website and it launches a Silverlight application, the Silverlight application will communicate with the web services of the site using the authentication token that was created when the user logged into the website.

Therefore, we need only to check the users credentials in the web service to determine if they should have access.

 

The Sample Program

In the sample program, we have a simple drop down that logs in as User One or User Two, and also logs out completely.

The first step is to enable Windows Forms Authentication in the web.config:

 

image

 

Next, the following code is used to log in and out:

 

    #region LogUserIn
    private void LogUserIntoSite(int intUser)
    {
        // Log the user into the site
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
            intUser.ToString(),
            DateTime.Now,
            DateTime.Now.AddDays(30),
            false,
            "Role One",
            FormsAuthentication.FormsCookiePath);

        // Encrypt the ticket.
        string encTicket = FormsAuthentication.Encrypt(ticket);

        // Create the cookie.
        Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
    }
    #endregion

    #region LogOut
    protected void LogOut()
    {
        FormsAuthentication.SignOut();
    }
    #endregion

 

In the WCF web service (Service.svc.cs), we use this code to create an Entity:

 

    [EntityPropertyMappingAttribute("CustomerName", 
        SyndicationItemProperty.Title, 
        SyndicationTextContentKind.Plaintext, true)]

    [DataServiceKey("RecordID")]
    public class CustomerRecord
    {
        // Note the RecordID is the DataServiceKey
        // It must be a unique value across the entire collection
        public int RecordID { get; set; }
        public int CustomerID { get; set; }
        public string CustomerName { get; set; }
        public string CustomerEmail { get; set; }
        public string CustomerNotes { get; set; }
        public DateTime CustomerLastContact { get; set; }
    }

 

We use this code to create a Data Source that uses the Entity (we create 10 records for 2 users):

 

    public SampleDataSource()
    {
        int intRecord = 0;
        for (int intUser = 1; intUser < 3; intUser++)
        {
            for (int i = 0; i < 10; i++)
            {
                CustomerRecord CR = new CustomerRecord();

                CR.RecordID =  intRecord;
                CR.CustomerID =  intUser;
                CR.CustomerName = string.Format("Name {0}-{1}", i.ToString(), intUser.ToString());
                CR.CustomerEmail = string.Format("Email{0}@{1}.com", i.ToString(), intUser.ToString());
                CR.CustomerNotes = string.Format("Notes {0}-{1} / {0}-{1}", i.ToString(), intUser.ToString());
                CR.CustomerLastContact =  DateTime.Now.AddDays(-10000).AddHours(i);

                _sampleCustomerRecordList.Add(CR);
                intRecord++;
            }
        }
    }

 

We use this code to expose this Data Source as a WCF DataService:

 

    public class Service : DataService<SampleDataSource>
    {
        // This method is called only once to initialize service-wide policies.  
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
            config.MaxResultsPerCollection = 100;
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }

 

Now, we previously exposed the OData point using code like this:

 

    public IQueryable<CustomerRecord> SampleCustomerData
    {
        get
        {
            return _sampleCustomerRecordList.AsQueryable();
        }
    }

 

To add security, we expose the OData point with this code (we determine if the user is logged in. If they are we only show the records that match their User ID):

 

    public IQueryable<CustomerRecord> SampleCustomerData
    {
        get
        {
            // Ensure user is authenticated
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                // Get the current user
                int intUser = 
                    Convert.ToInt32(HttpContext.Current.User.Identity.Name);

                // Filter results
                var result = 
                    _sampleCustomerRecordList.Where(x => x.CustomerID == intUser).ToList();

                // Return results
                return result.AsQueryable();
            }
            else
            {
                // Not Authenticated
                var result = new List<CustomerRecord>();
                return result.AsQueryable();
            }
        }
    }

 

Yeah that’s it. Basically we simply look at: HttpContext.Current.User.Identity.IsAuthenticated and HttpContext.Current.User.Identity.Name.

The Silverlight part is covered in the previous Blog (http://openlightgroup.net/Blog/tabid/58/EntryId/99/Simple-Silverlight-4-Example-Using-oData-and-RX-Extensions.aspx).

Note, When deploying on a Windows 2003 server, you will need to uncheck Windows Intergrated Authentication for the website in IIS. Also you need to set compilation debug="false" in the web.config. 

Further Reading

 

Sample Code

Download the sample at this link:

http://silverlight.adefwebserver.com/ODataAuthenticationSample/ODataAuthenticationSample.zip





Comments are closed.
Showing 2 Comments
Avatar  Michael Washington 6 years ago

@Rahman - That is incorrect. There is code in the SampleCustomerData method that stops the data from being returned.

Avatar  Rahman 6 years ago

What is it to do with odata security???&lt;br /&gt;The users still can go to the URL in the browser and type the URL and see the data!