using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Configuration.Provider; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Web.Profile; using System.Xml.Linq; using Neo.Afx.Diagnostics; namespace Neo.Afx.Security { /// /// Defines a domain profile provider /// public class DomainProfileProvider : ProfileProvider { const string EventSource = "DomainProfileProvider"; const string ExceptionMessage = "An exception occurred. Please check the Event Log."; const string PrGetProfileForUser = "Security.Pr_GetProfileForUser"; // @UserName, @AuthMode ConnectionStringSettings _connectionStringSettings; string _connectionString; #region Properties #region WriteExceptionsToEventLog /// /// Gets or sets a value indicating whether exceptions are written to the event log. /// If false, exceptions are thrown to the caller, otherwise exceptions are written to the event log. /// public bool WriteExceptionsToEventLog { get; set; } #endregion #region ApplicationName /// /// Gets or sets the name of the application to store and retrieve role information for. /// public override string ApplicationName { get; set; } #endregion #endregion #region Initialize /// /// Initializes the provider. /// /// The friendly name of the provider. /// A collection of the name/value pairs representing the /// provider-specific attributes specified in the configuration for this provider. /// /// The name of the provider is null. /// /// /// The name of the provider has a length of zero. /// /// /// An attempt is made to call /// on a provider after the provider has already been initialized. /// public override void Initialize(string name, NameValueCollection config) { if(config == null) { throw new ArgumentNullException("config"); } if(name.Length == 0) { name = "DomainProfileProvider"; } if(String.IsNullOrEmpty(config["description"])) { config.Remove("description"); config.Add("description", "Simple domain profile provider"); } // Initialize the abstract base class. base.Initialize(name, config); if(config["applicationName"] == null || config["applicationName"].Trim() == "") { ApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath; } else { ApplicationName = config["applicationName"]; } // Initialize connection. _connectionStringSettings = ConfigurationManager.ConnectionStrings[config["connectionStringName"]]; if(_connectionStringSettings == null || _connectionStringSettings.ConnectionString.Trim() == "") { throw new ProviderException("Connection string cannot be blank."); } _connectionString = _connectionStringSettings.ConnectionString; } #endregion #region GetPropertyValues /// /// Gets the property values. /// /// The context. /// The properties. /// public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection properties) { var svc = new SettingsPropertyValueCollection(); if(properties.Count >= 1) { var userName = (string)context["UserName"]; foreach(SettingsProperty property in properties) { if(property.SerializeAs == SettingsSerializeAs.ProviderSpecific) { if(property.PropertyType.IsPrimitive || (property.PropertyType == typeof(string))) { property.SerializeAs = SettingsSerializeAs.String; } else { property.SerializeAs = SettingsSerializeAs.Xml; } } svc.Add(new SettingsPropertyValue(property)); } if(!string.IsNullOrEmpty(userName)) { GetProfileForUser(userName, svc); } } return svc; } #endregion #region GetProfileForUser void GetProfileForUser(string userName, SettingsPropertyValueCollection properties) { try { using(var conn = new SqlConnection(_connectionString)) { using(var cmd = conn.CreateCommand()) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = PrGetProfileForUser; cmd.Parameters.AddWithValue("@UserName", userName); cmd.Parameters.AddWithValue("@AuthMode", DomainAuthenticationProvider.AuthenticationMode.ToString()); cmd.Connection.Open(); using(var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { if(reader.Read()) { for(int i = 0; i < reader.FieldCount; i++) { var name = reader.GetName(i); var value = properties[name]; if(value != null) { if(Convert.IsDBNull(reader[i])) { var fieldType = reader.GetFieldType(i); if(fieldType != null) { // value types (including structs) always have a default parameterless constructor value.PropertyValue = fieldType.IsValueType ? Activator.CreateInstance(fieldType) : null; } } else { if(name == "Settings") { var settings = new NameValueCollection(); foreach(var s in XElement.Parse(reader[i].ToString()).Elements()) { var s2 = XElement.Parse(s.ToString()); var settingName = (XElement)s2.FirstNode; var settingValue = (XElement)s2.LastNode; settings.Add(settingName.Value, settingValue.Value); } value.PropertyValue = settings; } else if(name == "WorkflowBuddies") { List> settings = new List>(); foreach(var s in XElement.Parse(reader[i].ToString()).Elements()) { var s2 = XElement.Parse(s.ToString()); var settingName = (XElement)s2.FirstNode; var settingValue = (XElement)s2.LastNode; settings.Add(new KeyValuePair(Convert.ToInt64(settingName.Value), Convert.ToInt64(settingValue.Value))); } value.PropertyValue = settings; } else if(name == "Securables") { value.PropertyValue = (from e in XElement.Parse(reader[i].ToString()).Elements() select e into secElem let secID = secElem.Element(XName.Get("SecurableID")).Value let canRead = secElem.Element(XName.Get("CanRead")).Value let canEdit = secElem.Element(XName.Get("CanEdit")).Value select new UserProfile.Securable { SecurableID = long.Parse(secID), CanRead = (canRead == "1" ? true : false), CanEdit = (canEdit == "1" ? true : false) }); } else if(name == "Roles") { value.PropertyValue = XElement.Parse(reader[i].ToString()).Elements().Select(x => Int32.Parse(x.Value)).ToArray(); } else { value.PropertyValue = reader[i]; } } value.IsDirty = false; value.Deserialized = true; } } } else { #region User doesn't exist - create empty profile properties for(var i = 0; i < reader.FieldCount; i++) { var name = reader.GetName(i); var value = properties[name]; if(value != null) { var type = reader.GetFieldType(i); if(type != null) { value.PropertyValue = type.IsValueType ? Activator.CreateInstance(type) : null; } value.IsDirty = false; value.Deserialized = true; } } #endregion } } } } } catch(SqlException e) { if(WriteExceptionsToEventLog) { LogUtility.WriteApplicationEventLog(e); throw new ProviderException(ExceptionMessage); } throw; } } #endregion #region Not implemented methods /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are deleted. /// A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. /// /// The number of profiles deleted from the data source. /// public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); } /// /// Not implmented /// /// A string array of user names for profiles to be deleted. /// /// The number of profiles deleted from the data source. /// public override int DeleteProfiles(string[] usernames) { throw new NotImplementedException(); } /// /// Not implmented /// /// A of information about profiles that are to be deleted. /// /// The number of profiles deleted from the data source. /// public override int DeleteProfiles(ProfileInfoCollection profiles) { throw new NotImplementedException(); } /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. /// The user name to search for. /// A that identifies which user profiles are considered inactive. If the value of a user profile occurs on or before this date and time, the profile is considered inactive. /// The index of the page of results to return. /// The size of the page of results to return. /// When this method returns, contains the total number of profiles. /// /// A containing user profile information for inactive profiles where the user name matches the supplied parameter. /// public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. /// The user name to search for. /// The index of the page of results to return. /// The size of the page of results to return. /// When this method returns, contains the total number of profiles. /// /// A containing user-profile information for profiles where the user name matches the supplied parameter. /// public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. /// A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. /// The index of the page of results to return. /// The size of the page of results to return. /// When this method returns, contains the total number of profiles. /// /// A containing user-profile information about the inactive profiles. /// public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. /// The index of the page of results to return. /// The size of the page of results to return. /// When this method returns, contains the total number of profiles. /// /// A containing user-profile information for all profiles in the data source. /// public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords) { throw new NotImplementedException(); } /// /// Not implmented /// /// One of the values, specifying whether anonymous, authenticated, or both types of profiles are returned. /// A that identifies which user profiles are considered inactive. If the of a user profile occurs on or before this date and time, the profile is considered inactive. /// /// The number of profiles in which the last activity date occurred on or before the specified date. /// public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate) { throw new NotImplementedException(); } /// /// Not implmented /// /// A describing the current application usage. /// A representing the group of property settings to set. public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) { throw new NotImplementedException(); } #endregion } }