namespace VAL
{
using System;
using System.Configuration;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using VAL.Common;
using VAL.Common.Properties;
/// <summary>
/// WorkgroupHelper helps when new users are being created by cloning user
/// permissions in the main network workgroup used to secure MS Access
/// database
/// </summary>
public class WorkgroupHelper : IDisposable
{
private const int adStateOpen = 1;
/// <summary>
/// Access to the log4Net logging object
/// </summary>
protected static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Type connectionType;
private Type catalogueType;
private object connection;
private object catalogue;
private bool disposed;
/// <summary>
/// Default ctor
/// </summary>
public WorkgroupHelper()
{
connectionType = Type.GetTypeFromProgID("ADODB.Connection");
connection = Activator.CreateInstance(connectionType);
catalogueType = Type.GetTypeFromProgID("ADOX.Catalog");
catalogue = Activator.CreateInstance(catalogueType);
Connect();
}
/// <summary>
/// Creates a new user in the workgroup and clones all the permissions for
/// the user from a source user
/// </summary>
/// <param name="sourceUser">The user to base the new user on. Clones permissions</param>
/// <param name="user">The user to create</param>
public void CloneUser(string sourceUser, string user)
{
try
{
InvokeMethod(connectionType, connection, "BeginTrans");
CreateUser(user);
List<string> groups = GetUsersGroups(sourceUser);
foreach (var group in groups)
{
AddUserToGroup(user, group);
}
InvokeMethod(connectionType, connection, "CommitTrans");
}
catch (Exception ex)
{
InvokeMethod(connectionType, connection, "RollbackTrans");
log.Error(ex.Message, ex);
throw;
}
}
private void InvokeMethod(Type targetType, object target, string methodName)
{
targetType.InvokeMember(methodName,
System.Reflection.BindingFlags.InvokeMethod,
null,
target,
null);
}
/// <summary>
/// Connects to the database via the enterprise workgroup
/// </summary>
private void Connect()
{
string workgroup = Session.Configuration.EnterpriseWorkgroupDirectory + Session.Configuration.EnterpriseWorkgroupName;
if (string.IsNullOrEmpty(workgroup))
throw new ConfigurationErrorsException(Resources.EnterpriseWorkgroupException);
if (!File.Exists(workgroup))
throw new FileNotFoundException("The enterprise workgroup definied in the application configuration file could not be found");
if (!File.Exists(Session.Configuration.AccessDatabaseLocation))
throw new FileNotFoundException("The access database defined in the application configuration file could not be found");
string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=";
connectionString += Session.Configuration.AccessDatabaseLocation;
connectionString += ";Jet OLEDB:System Database=" + workgroup;
string decryptedAdminPassword = EncryptionHelper.Decrypt(Session.Configuration.EnterpriseAdminPassword,
Session.Configuration.EnterpriseAdminUserName);
connectionType.InvokeMember("Open",
BindingFlags.InvokeMethod,
null,
connection,
new object[] { connectionString,
Session.Configuration.EnterpriseAdminUserName,
decryptedAdminPassword,
0
});
catalogueType.InvokeMember("ActiveConnection",
BindingFlags.SetProperty,
null,
catalogue,
new object[] {connection});
}
/// <summary>
/// Creates a user in the workgroup
/// </summary>
/// <param name="userName"></param>
private void CreateUser(string userName)
{
object users = catalogueType.InvokeMember("Users",
BindingFlags.GetProperty,
null,
catalogue,
null);
object user = GetUser(userName);
if (user != null)
catalogueType.InvokeMember("Delete",
BindingFlags.InvokeMethod,
null,
users,
new object[] { userName });
catalogueType.InvokeMember("Append",
BindingFlags.InvokeMethod,
null,
users,
new object[] { userName, string.Empty });
if (user != null)
{
Marshal.ReleaseComObject(user);
}
}
/// <summary>
/// Adds the specified user to a group
/// </summary>
/// <param name="userName">the user to add to the group</param>
/// <param name="groupName">the name of the group to add them to</param>
private void AddUserToGroup(string userName, string groupName)
{
try
{
object user = GetUser(userName);
object groups = catalogueType.InvokeMember("Groups",
BindingFlags.GetProperty,
null,
user,
null);
catalogueType.InvokeMember("Append",
BindingFlags.InvokeMethod,
null,
groups,
new object[] {groupName});
}
catch
{
// will throw exception if user already belongs to group, ignore
}
}
private object GetUser(string userName)
{
object user = null;
try
{
user = catalogueType.InvokeMember("Users",
BindingFlags.GetProperty,
null,
catalogue,
new object[] { userName });
}
catch (Exception ex)
{
log.Error(string.Format("Could not get user object for {0}", userName), ex);
}
return user;
}
/// <summary>
/// Gets the groups a user is a member of
/// </summary>
/// <param name="userName">the username to get the groups from</param>
/// <returns>ArrayList of groups</returns>
private List<string> GetUsersGroups(string userName)
{
List<string> usersGroups = new List<string>();
object user = GetUser(userName);
if (user != null)
{
object groups = catalogueType.InvokeMember("Groups",
BindingFlags.GetProperty,
null,
user,
null);
int length = (int)catalogueType.InvokeMember("Count",
BindingFlags.GetProperty,
null,
groups,
null);
for (int i = 0; i < length; ++i)
{
object group = catalogueType.InvokeMember("Item",
BindingFlags.GetProperty,
null,
groups,
new object[] {i});
string groupName = catalogueType.InvokeMember("Name",
BindingFlags.GetProperty,
null,
group,
null).ToString();
usersGroups.Add(groupName);
}
Marshal.ReleaseComObject(user);
}
return usersGroups;
}
#region Implementation of IDisposable
/// <summary>
/// Protected overide of the Dispose pattern
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Clean up our COM objects
if (connection != null)
{
int connectionState = (int)connectionType.InvokeMember("State",
BindingFlags.GetProperty,
null,
connection,
null);
// Close the connection if it's open
if (connectionState == adStateOpen)
{
InvokeMethod(connectionType, connection, "Close");
}
Marshal.ReleaseComObject (connection);
Marshal.ReleaseComObject (catalogue);
}
}
disposed = true;
}
}
/// <summary>
/// Dispose of the object
/// </summary>
public void Dispose()
{
Dispose(true);
}
#endregion
}
}