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
}
}