Application Security, Part 24
Here is the code for the main form of our Smart Client that handles the event of the user changing his or her language preference.
private bool fLanguage_Switch(string sLanguage, System.Windows.Forms.MenuItem rMenuItem)
{
try
{
if(!(frmMain.fLanguage_CheckMenuItem(rMenuItem)))
{
return false;
}
((CUser)Thread.CurrentPrincipal).PreferredLanguage = sLanguage;
frmMain.fRestart = true;
this.Close();
return true;
}
catch(Exception)
{
return false;
}
}
We see that it assigns the new preferred language to the PreferredLanguage property of a user object. Let us see what that entails.
using System;
using System.DirectoryServices;
using System.Net;
using System.Security.Principal;
using Utility = Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.Utility;
using UserService = iTaskVisionII.UserService;
namespace Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.TaskVisionII.Presentation
{
public class CUser: Utility.CUser
{
private const string c_sConfigurationSection_User = @"User";
private const string c_sKey_Location_Service = @"Location_Service";
private ICredentials rCredentials;
public CUser(string sName,string sLanguage_Preferred,bool[] afPermissions,ICredentials rCredentials,string[] asRoles):base(sName,sLanguage_Preferred,afPermissions,asRoles)
{
this.rCredentials = rCredentials;
}
public override string PreferredLanguage
{
get
{
return base.PreferredLanguage;
}
set
{
try
{
base.PreferredLanguage = value;
System.Collections.Hashtable rConfigurationSection = (System.Collections.Hashtable)System.Configuration.ConfigurationSettings.GetConfig(CUser.c_sConfigurationSection_User);
UserService.TaskVisionII_User rUserService = new UserService.TaskVisionII_User();
rUserService.Url = (string)rConfigurationSection[CUser.c_sKey_Location_Service];
rUserService.Credentials = this.rCredentials;
UserService.CUser rUser = new UserService.CUser();
rUser.sName = this.Name;
rUser.sLanguage_Preferred = this.PreferredLanguage;
rUser.afPermissions = this.Permissions;
bool f = rUserService.fPersistPreference_Language(rUser);
}
catch(Exception)
{
}
}
}
public ICredentials Credentials
{
set
{
this.rCredentials = value;
}
}
/*
#region IIdentity Members
public bool IsAuthenticated
{
get
{
return this.fIsAuthenticated;
}
}
public string Name
{
get
{
if(this.IsAuthenticated)
{
return this.Identifier;
}
else
{
return null;
}
}
}
public string AuthenticationType
{
get
{
if(this.IsAuthenticated)
{
return CUser.c_sAuthenticationType_Kerberos;
}
else
{
return null;
}
}
}
#endregion
*/
}
}
Remember that the user’s language preference is stored in ADAM, so when the user changes his or preference, the new choice must be registered there. Thus, we see that the code invokes a User Web Service that will be assigned the task of recording the user’s language preference in ADAM on the server. The code for that Web Service is extremely simple.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Web;
using System.Web.Services;
using Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.Service;
namespace Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.Service
{
public class TaskVisionII_User : System.Web.Services.WebService
{
public TaskVisionII_User()
{
//CODEGEN: This call is required by the ASP.NET Web Services Designer
InitializeComponent();
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
[WebMethod]
public bool fPersistPreference_Language(CUser rUser)
{
try
{
ActiveDs.IADsUser rUser_ADAM = CADAM.rGetUser(rUser.sName);
rUser_ADAM.Put(@"preferredLanguage",rUser.sLanguage_Preferred);
rUser_ADAM.SetInfo();
return true;
}
catch(Exception rException)
{
return false;
}
}
}
}
It merely uses that GetUser method of that class we looked at earlier—the one that knows how to talk to ADAM—to retrieve the user object from ADAM. Then the service updates the preferred language attribute of that object and saves the change.
Sidenote: You may recall from Part 23, that the code for the static main method of the Smart Client took the user data that it retrieved from the authentication Web Service and did this:
Thread.CurrentPrincipal = new CUser(rUser.sName,rUser.sLanguage_Preferred,rUser.afPermissions,rCredentials,rUser.asRoles);
That served to associate the data for the user retrieved from ADAM with Windows Forms internal record of data about the current user, which is handy for, amongst other things, controlling access to methods using the authorization facilities built into .NET . . . which we won't be, but nonetheless: the CurrentPrincipal property of the current thread is where runtime user data belongs, so we are following the good practice of putting it there. We defined this class to serve as the container for our custom set of user data:
using System;
using System.Security.Principal;
namespace Microsoft.DeveloperAndPlatformEvangelism.Demonstrations.Utility
{
public class CUser: GenericPrincipal,IIdentity
{
private const string c_sAuthenticationType_Kerberos = @"Kerberos";
private string sLanguage_Preferred = null;
private bool[] afPermissions = null;
private bool fAuthenticated = false;
public CUser(string sName,string sLanguage_Preferred,bool[] afPermissions,string[] asRoles):base(new GenericIdentity(sName,CUser.c_sAuthenticationType_Kerberos),asRoles)
{
this.sLanguage_Preferred = sLanguage_Preferred;
this.afPermissions = afPermissions;
this.fAuthenticated = true;
}
public virtual string PreferredLanguage
{
get
{
return this.sLanguage_Preferred;
}
set
{
this.sLanguage_Preferred = value;
}
}
public bool[] Permissions
{
get
{
return this.afPermissions;
}
set
{
this.afPermissions = value;
}
}
#region IIdentity Members
public string Name
{
get
{
if(this.IsAuthenticated)
{
return this.Identity.Name;
}
else
{
return null;
}
}
}
public string AuthenticationType
{
get
{
if(this.IsAuthenticated)
{
return this.Identity.AuthenticationType;
}
else
{
return null;
}
}
}
public bool IsAuthenticated
{
get
{
return this.fAuthenticated;
}
}
#endregion
}
}
The CUser class for which the code was shown at the top of this post is a descendant of the CUser class defined above.