Client Application Services - Part 2
 
Published: 14 Mar 2008
Abstract
In this second part of the series, Bilal Haidar demonstrates how to authenticate and authorize users accessing a Windows Forms application by using Client Application Services introduced with Visual Studio 2008 and .NET 3.5. He starts with a brief description of Web application host and then examines authentication and authorization aspects involved with its creation. Bilal also shows how to test the Visual Studio 2008 application and provides the whole project for download.
by Bilal Haidar
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 42212/ 122

Overview

In part one of this series, we have introduced to you the ASP.NET 2.0 application services including Membership, Role, and Profile services. These services can be configured in a matter of few minutes inside the Web.config configuration file and you can start making use of them in your application.

In addition, ASP.NET 2.0 AJAX 1.0 Extensions application services were covered too. These are client-side services that allow applications, from the client-side JavaScript, to contact the application services on the server. What happens is that, when you configure your application to work with application services using JavaScript, client-side proxies will be created on the client side to make it an easy task for the JavaScript code to access the server services.

Moreover, a detailed overview was given on the Client Application Services introduced by Visual Studio 2008 and .NET 3.5 that allows client applications including Windows Forms and Windows Presentation Foundation applications to access the same database used for user management by web and Ajax application. This feature depends on the ASP.NET 2.0 AJAX 1.0 Extensions application services.

In this article we will demonstrate how to create a Web application to host the ASP.NET 2.0 AJAX 1.0 Extensions Application Services, create a Windows Forms application that will enable authentication and authorization and show you how this client application will contact the web host application for the purpose of authenticating users and authorizing them to access specific sections of the resources present in the application.

Web application host

In order to allow a client application to access the ASP.NET application services, there is a need to create an ASP.NET web application that will function as a host to access the Membership, Role, and Profile services.

The client application will then reference that host application to enable remote access to the services needed.

To start with, we will develop the ASP.NET application and enable only the Membership and Role services for this article.

First of all, create a new ASP.NET website called ASP.NETApplicationServices. The Membership service is enabled automatically and it is configured by default to work with a database located in a SQL Server 2005 Express edition. To change this configuration and allow the Membership service to interact with another database of your own, simply add the following in the web.config configuration file.

Listing 1

<connectionStrings>
<remove name="LocalSqlServer"/>
<add connectionString="Data Source=.\SQL2005;Initial 
Catalog=ClientApplicationServices;Integrated Security=True" name="LocalSqlServer"
providerName="System.Data.SqlClient"/>
</connectionStrings>

The default connection string used is named LocalSqlServer, so by removing it first and then adding it with different connection string properties, allows the configured Membership provider to interact with the database specified.

One addition step is left which is to install the ASP.NET 2.0 Application Services database. This will not be explained in this article, but this blog post shows in details how to do so: Install Application Services Database on Microsoft SQL Server 2000/2005.

What we need is to enable Role management for this application. This can be easily done by adding this configuration section to the web.config configuration file.

Listing 2

<roleManager enabled="true" /> 

Now that the application is configured for Membership and Role management services, a final step is required to give this website a fixed port number since it is using the Visual Studio 2008 internal web server. This is very important in case you are developing the host application as a website which means every time you run this website, VS 2008 will generate a new port number and assign it to the website and this breaks down the connection between the client application and this host application. To remedy the situation, a fixed port number is necessary so that every time VS 2008 runs this website, it will use the same port number. This can be done by accessing the properties page of the website and clicking on the Web tab. If you look under the Servers section, you can find a radio button called Specific port. There you can set the port number you want as shown in Figure 1.

Figure 1: ASP.NET website Web tab

The current configuration is enough to start creating the client application to authenticate and authorize users.

Client Application

For the sake of this application, we will create a new Windows Forms application. Once you create the application, go to the properties page of the application and then access the Services tab. This new tab has been added with Visual Studio 2008 and it allows you to configure your application to use client application services. Figure 2 shows the services tab.

Figure 2: Windows Forms Services tab

First of all, the client application services should be enabled by selecting the checkbox shown in the figure above.

Authentication

Once the client application services are enabled, you can configure what type of authentication to use. For the sake of this article, Forms authentication will be used. Once the radio button Use Forms Authentication is selected, you should provide the remote authentication service location. In this case it is the URL for the ASP.NET website host application that was created in a previous section of this article. When it is time to access the remote authentication service, the Client Application Services framework adds the Authenticate_JSON_AppService.axd to the configured URL. This is the URL for the HttpHandler that will access the configured Membership provider set by the ASP.NET website host application.

The next entry to set is the Credentials provider. As mentioned in part 1 of this article, this should point to the Login form that will be used to gather credentials from the user to authenticate against the remote authentication service. As we will see soon, the Login form will implement the IClientFormsAuthenticationCredentialsProvider interface and provide code for the GetCredentials method. This method will be called when you issue a call to the Membership.ValidateUser method later in the application.

Finally, you should set the URL for the Roles service. The same URL will be used here and again, the Client Application Service framework will append to the URL the Role_JSON_AppService.axd HttpHandler path that will be used to access the remote Roles service.

Now that the Client Application Service is enabled, it is time to create the Login form. We do this by adding a new Windows Form called Login.cs. This form, as mentioned before, should implement the IClientFormsAuthenticationCredentialsProvider interface and provide a method called GetCredentials that will return an instance of ClientFormsAuthenticationCredentials object filled with the credentials entered by the user. The implementation of the form is quiet simple and is shown below.

Listing 3

namespace ClientApplication
{
  public partial class Login: Form,
    IClientFormsAuthenticationCredentialsProvider
  {
    public Login()
    {
      InitializeComponent();
    }
 
    #region IClientFormsAuthenticationCredentialsProvider Members
    public ClientFormsAuthenticationCredentials GetCredentials()
    {
      if (this.ShowDialog() == DialogResult.OK)
      {
        return new ClientFormsAuthenticationCredentials(this.txtUsername.Text,
          this.txtPassword.Text, false);
      }
      else
      {
        return null;
      }
    }
    #endregion
  }
}

You can see how simple it is with the implementation of the GetCredentials method. It shows the Login form and waits for the OK button to be clicked, and then it returns an instance of the ClientFormsAuthenticationCredentials containing the credentials entered by the user.

After developing the Login form, we will create the main applications’ form. In the Form_Load event of this form, we will issue a call to validate the user as shown below.

Listing 4

private void Form1_Load(object sender, EventArgs e)
{
  // Validate the user
  if (!ValidateUser())
    return ;
 
  // Fill user information
  DisplayUserInfo();
}
 
private bool ValidateUser()
{
  bool isAuthenticated = false;
  try
  {
    isAuthenticated = Membership.ValidateUser(string.Empty, string.Empty);
  }
  catch (System.Net.WebException ex)
  {
    // a WebException is raised when the authentication service
    // cannot be reached
    if (DialogResult.OK == MessageBox.Show(
      "Unable to access the authentication service""Not logged in",
      MessageBoxButtons.OK, MessageBoxIcon.Error))
      Application.Restart();
  }
 
  if (!isAuthenticated)
  {
    MessageBox.Show("Unable to authenticate credentials""Not logged in",
      MessageBoxButtons.OK, MessageBoxIcon.Error);
    Application.Exit();
  }
 
  return isAuthenticated;
}

In the Form_Load event there is a call to ValidateUser method which calls the Membership.ValidateUser method. Calling this method with empty string is a must so that the credentials login form pops up.

If the authentication service is unavailable, then a System.Net.WebException is thrown. If ValidateUser method returns true, the current user is now authenticated and an authentication cookie is now created for the user on the local hard disk.

In addition, there is a call for the method DisplayUserInfo. This method shall bind a label on the main form to some information about the user, mainly a welcome message, and display the authentication type.

Listing 5

private void DisplayUserInfo()
{
  // Get the ClientFormsIdentity
  ClientFormsIdentity user = (ClientFormsIdentity)
    System.Threading.Thread.CurrentPrincipal.Identity;
  StringBuilder sb = new StringBuilder();
  sb.AppendFormat("Welcome {0} !! \r\n\r\n" + "Authentication Type: {1} \r\n",
    user.Name, user.AuthenticationType);
  this.label1.Text = sb.ToString();
}

Notice how we are retrieving an instance of the ClientFormsIdentity by casting the Identity property on the System.threading.Thread.CurrentPrincipal object.

Authorization

In this section we will retrieve some information related to the roles the user belongs to. Another method call is added to the Form_Load which is DisplayUserRoles. This method shall retrieve the roles that the user belongs to, if any, and bind the data to a DataGridView placed on the main form.

Listing 6

private void DisplayUserRoles()
{
  // Get the ClientRolePrincipal
  ClientRolePrincipal principal = (ClientRolePrincipal)
    System.Threading.Thread.CurrentPrincipal;
  // Get an instance of the ClientRoleProvider
  ClientRoleProvider roleProvider = (ClientRoleProvider)Roles.Provider;
 
  // Get user roles
  string[]roles = roleProvider.GetRolesForUser(principal.Identity.Name);
 
  panel1.Visible = roles.Length >= 1;
  if (panel1.Visible)
  {
    foreach (string s in roles)
      this.dataGridView1.Rows.Add(s);
  }
}

First of all, the code retrieves an instance of the ClientRolePrincipal from the CurrentPrincipal object on the System.Threading.Thread object. There is nothing special about this object except a method called IsInRole which accesses internally the ClientRoleProvider.IsUserInRole method.

Once the ClientRolePrincipal object is created, an instance of the ClientRoleProvider is cast from the Roles.Provider property. You could have directly used the Roles.Provider property to access the methods related to roles, but using an instance of ClientRoleProvider is better since it will show you which methods are implemented and which are not.

As mentioned in part 1 of this series, the role management in Client Application Services is read-only, you can only check whether the user is in a specific role or not by using the IsUserInRole method and another method to retrieve user roles called GetRolesForUser.

A call for the GetRolesForUser is issued to retrieve the user’s roles. If there are any roles for the currently logged in user, they are bound to a DataGridView on the main form.

Disable offline mode

So far, we have been explaining how to enable Client Application Services for live connection with the remote authentication and role providers. In the last section of this article, we will show how to configure an application to make use of offline mode which allows your application to authenticate users by accessing a cache of the credentials information stored locally on the application’s machine.

For the time being, you still need to do some configurations on your application to make it work with a none-offline mode. To do so, access the Advanced button located on the Services tab. Once the Advanced button is clicked, a popup windows pops up as shown in Figure 3.

Figure 3: Advanced settings form

To disable offline mode, make sure to uncheck all the checkboxes and to set the Role service cache timeout to 0, without this value you will not be able to retrieve roles-related information for the user. In the next article we will see how to enable offline mode for your application.

Testing the solution

When you first run the application, the Login form will popup asking you to enter your credentials as shown in Figure 4.

Figure 4: Login form

Once you enter your correct credentials, the main form will be displayed with all the data bound to it retrieved from the remote authentication and authorization services as shown below.

Figure 5: Main application form

As you can see, there is a welcome message for the user together with the authentication type which is, in this case, of type ClientForms. Finally, a DataGridView is showing the roles the currently logged in user belongs to.

Downloads

References

Material is still scarce on this topic, but there is a very informative section on the MSDN library that allows you to get an idea on all the details that surround Client Application Services. Follow this link to access this information: Client Application Services.

Conclusion

In this article we have shown you how to utilize the Client Application Services by first creating a new ASP.NET website host application. This application enables the Membership and Role management services together with enabling ASP.NET 2.0 AJAX 1.0 Extensions services.

After that, a new windows client application was created and configured to access the remote authentication and role services.

This article is part 2 of a series of articles on the Client Application Services feature introduced with Visual Studio 2008 and .NET 3.5. The first article was an introductory article on the application services and CLAS. This article gave a better overview of the CLAS by providing a concrete example on how to use and access authentication and roles services. The third and last article will deal with accessing Profile service and Web settings in your Windows client application. In addition, we will show you how to configure your application with offline mode to perform all your operations of authenticating and authorizing users against local copy of their credentials and finally, how to provide a logout functionality for the user to logout from the application.

We hope you enjoyed this article and benefited from the information presented. If you have any questions or comments please feel free to contact me directly at bhaidar@gmail.com.

Happy Ajaxified Dot Netting!!!



User Comments

Title: Continuing last comment   
Name: Krishna Vedula
Date: 4/4/2010 7:22:11 PM
Comment:
Hello Bilal

Looks like there is a limit on the length of the comment. So, here are my details

Krishna Vedula
krishna@ntc-us.com
Title: How to pass the user context back to server   
Name: Krishna J Vedul
Date: 4/4/2010 7:21:12 PM
Comment:
Hello Bilal,

Great Series of articles going in depth in to each of the security topics. I found this very helpful. This helped me get a general direction for the project I am working on currently. However, I have come across a road-block in all articles related to Client Application Services across many sites and was not able to get much help in that regard.

What I am trying exactly is to have the same Authentication framework for my Web front-end as well as the Web interface. With Client Application Services, I am able to get that as explained by you clearly. I also get the roles of the user, so I control what to show and what not to show. Great so far.

I am going to the next level, where my Desktop application is connecting back to the same server (that server the authentication as well as web-content) to get some data. Here I have created some facades (aspx) to parse the request data and send the response as XML. I am able to use the same business objects with some custom aspx files for xml transformation. But, I am getting an error in the business layer if I put any security role restrictions.

How do I pass the Thread.CurrentPrincipal.Identity which has all the roles back to through the web request so that the security framework on the server would not throw any execptions.

a) Code I am using to create a request on the client is

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"http://localhost:55555/AppServices/GetAdminData.aspx");
req.Method = WebRequestMethods.Http.Post;

b) Security Permissions on the server are like


[PrincipalPermissionAttribute(SecurityAction.Demand, Role="admin")]
public void ProcessRequest()
{

If I could pass all the cookies that come from user authentication back to server as part of the request, then I woudl get over the problem. But with Membership.ValidateUser I do not get any cookies. Then how do I pass them?

The SaveUserSettings seems to send the user
Title: Good Article   
Name: Adron
Date: 10/20/2008 12:07:25 AM
Comment:
Good write up. I'm working through multiple scenarios right now with this, so it is interesting to read and helpful.

Thx.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2014 ASPAlliance.com  |  Page Processed at 10/24/2014 7:59:39 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search