//*****************************************************************************
// This code file is part of the Universal Provider Framework for SharePoint.
// This file was written by Adam Buenz [WSS MVP] of ARB Security Solutions, LLC
// http://www.sharepointsecurity.com
//
// This file and its parts is free for re-distribution, for use in both free
// and commercial applications, however this header must remain intact for legal
// use. The Universal Provider Framework is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//*****************************************************************************
//**************************************
// Current Version: 1.0.0.0 (Beta)
//**************************************
// namespace references
using System;
using System.Configuration.Provider;
using System.Data;
using System.Data.Common;
using System.Runtime.InteropServices;
using System.Web.Security;
namespace Universal.SharePointProvider.Framework
{
internal class SharePointUsersProvider
{
///
/// Declare constructor for the SharePointUsersProvider class
///
///
///
///
public SharePointUsersProvider(ProviderBase owner, DbProviderFactory provider, string applicationName)
{
this.owner = owner;
this.applicationName = applicationName;
this.provider = provider;
}
///
/// Declare variables
///
private readonly string applicationName;
private readonly ProviderBase owner;
private readonly DbProviderFactory provider;
///
/// Declare properties
///
private string ApplicationName
{
get
{
return this.applicationName;
}
}
private string Name
{
get
{
return this.owner.Name;
}
}
///
/// Declare enumeration for the provider type
///
public enum ProviderType
{
All = 7,
Membership = 1,
Profile = 4,
Role = 2
}
///
/// General parameter information
///
///
///
///
protected virtual void ApplyParameterInfo(DbParameter parameter, DbType dbType, object value)
{
// Set the DBtype parameter
parameter.DbType = dbType;
// Set the value of the parameter
parameter.Value = value;
}
///
/// Database command and connection
///
///
///
///
private DbCommand CreateCommand(string commandText, DbConnection connection)
{
DbCommand userProviderDbCommand = this.provider.CreateCommand();
userProviderDbCommand.Connection = connection;
userProviderDbCommand.CommandText = commandText;
return userProviderDbCommand;
}
///
///
///
///
///
///
///
private DbParameter CreateParameter(string name, DbType dbType, object value)
{
DbParameter userProviderParameterCommand = this.provider.CreateParameter();
userProviderParameterCommand.ParameterName = name;
this.ApplyParameterInfo(userProviderParameterCommand, dbType, value);
return userProviderParameterCommand;
}
///
/// General parameters of the factory implemenation
///
///
///
///
///
///
private DbParameter CreateParameter(string name, DbType dbType, int size, object value)
{
DbParameter userProviderParameterCommand = this.provider.CreateParameter();
userProviderParameterCommand.ParameterName = name;
userProviderParameterCommand.Size = size;
this.ApplyParameterInfo(userProviderParameterCommand, dbType, value);
return userProviderParameterCommand;
}
///
/// Create the user in the membership data store
///
///
///
///
///
///
///
///
public object CreateUser(DbConnection conn, bool isAnonymous, string username, object userId, bool userMustNotExist, out MembershipCreateStatus status)
{
IDbCommand createUserDbCommand = null;
bool flagValid;
// Determine whether the creation status resulted in success
status = MembershipCreateStatus.Success;
object objOutput = null;
// Get various information related to the user
objOutput = this.GetMembershipByUserName(conn, "username", DbType.String, username.ToLower(), out flagValid, false);
if (objOutput != null)
{
if (userMustNotExist || ((userId != null) && (((Guid) objOutput) != ((Guid) userId))))
{
// Declare whether the creation status results in a duplicate username
status = MembershipCreateStatus.DuplicateUserName;
return objOutput;
}
if (!flagValid && !isAnonymous)
{
createUserDbCommand = this.CreateCommand("UPDATE aspnet_users SET lastactivitydate = :lastactivitydate, isanonymous = FALSE WHERE userid = :userid ", conn);
createUserDbCommand.Parameters.Add(this.CreateParameter("lastactivitydate", DbType.DateTime, DateTime.Now));
createUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, userId));
createUserDbCommand.ExecuteNonQuery();
}
return objOutput;
}
if (string.IsNullOrEmpty(username))
{
// determine whether the creation status resulted in an invalid username
status = MembershipCreateStatus.InvalidUserName;
return objOutput;
}
// Get the current Date/Time for the insert of user into the data store
DateTime currentTime = DateTime.Now;
createUserDbCommand = this.CreateCommand("INSERT INTO aspnet_users ( lastactivitydate, applicationname, username, userid, isanonymous) VALUES ( :lastactivitydate, :applicationname, :username, :userid, :isanonymous)", conn);
createUserDbCommand.Parameters.Add(this.CreateParameter("lastactivitydate", DbType.DateTime, currentTime));
// Throw an error message if there are insatisfactions with the userID
if ((userId != null) && !(userId is Guid))
{
throw new ArgumentException("userid");
}
// determine whether the GUID is null
if (userId == null)
{
// Create a new GUID if the GUID is null
userId = Guid.NewGuid();
}
// Add various parameters to the database
createUserDbCommand.Parameters.Add(this.CreateParameter("applicationname", DbType.String, 0xff, this.ApplicationName));
createUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, userId));
createUserDbCommand.Parameters.Add(this.CreateParameter("username", DbType.String, 0xff, username));
createUserDbCommand.Parameters.Add(this.CreateParameter("isanonymous", DbType.Boolean, isAnonymous));
createUserDbCommand.ExecuteNonQuery();
return userId;
}
///
/// Delete the user from the database
///
///
///
///
///
public bool DeleteUser(DbConnection conn, string username, ProviderType providerType)
{
bool flagValidate;
string textQuery;
int primaryCounter = 0;
int secondaryCounter = 0;
//dbObject can be customized to query data type
object dbObject = null;
dbObject = this.GetMembershipByUserName(conn, "username", DbType.String, username.ToLower(), out flagValidate, false);
// determine if the username is null, if so the user can't be deleted
if (dbObject == null)
{
return false;
}
//DB Command line
IDbCommand deleteUserDbCommand = null;
// Determine if the provider type is that of a pluggable role provider
if ((providerType & ProviderType.Role) > ((ProviderType) 0))
{
deleteUserDbCommand = this.CreateCommand("DELETE FROM aspnet_usersinroles WHERE userid = :userid", conn);
deleteUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, dbObject));
try
{
//execute nonquery for "delete and insert", if the return is 0 so for error handling
if (deleteUserDbCommand.ExecuteNonQuery() > 0)
{
primaryCounter++;
}
secondaryCounter++;
}
catch (Exception exception)
{
throw exception;
}
}
else if (this.GetRecordCount(conn, "aspnet_usersinroles", dbObject) == 0)
{
secondaryCounter++;
}
// determine if the provider type is that of a profile
if ((providerType & ProviderType.Profile) > ((ProviderType) 0))
{
// Remove the user based on userID from arbitrary profiles
textQuery = "DELETE FROM aspnet_profiles WHERE userid = :userid";
// determine whether the command is empty, and if so populate with the textQuery
if (deleteUserDbCommand == null)
{
deleteUserDbCommand = this.CreateCommand(textQuery, conn);
}
else
{
deleteUserDbCommand.CommandText = textQuery;
deleteUserDbCommand.Parameters.Clear();
}
deleteUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, dbObject));
try
{
if (deleteUserDbCommand.ExecuteNonQuery() > 0)
{
primaryCounter++;
}
secondaryCounter++;
}
catch
{
}
}
else if (this.GetRecordCount(conn, "aspnet_profiles", dbObject) == 0)
{
secondaryCounter++;
}
// Determine if the provider type is that of membership
if ((providerType & ProviderType.Membership) > ((ProviderType) 0))
{
// Remove the user from the various points of membership based on UserID
textQuery = "DELETE FROM aspnet_membership WHERE userid = :userid";
if (deleteUserDbCommand == null)
{
deleteUserDbCommand = this.CreateCommand(textQuery, conn);
}
else
{
deleteUserDbCommand.CommandText = textQuery;
deleteUserDbCommand.Parameters.Clear();
}
deleteUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, dbObject));
try
{
if (deleteUserDbCommand.ExecuteNonQuery() > 0)
{
primaryCounter++;
}
secondaryCounter++;
}
catch (Exception exception)
{
throw exception;
}
}
else if (this.GetRecordCount(conn, "aspnet_membership", dbObject) == 0)
{
secondaryCounter++;
}
if (((providerType & ProviderType.All) == ProviderType.All) || (secondaryCounter == 3))
{
textQuery = "DELETE FROM aspnet_users WHERE userid = :userid";
if (deleteUserDbCommand == null)
{
deleteUserDbCommand = this.CreateCommand(textQuery, conn);
}
else
{
deleteUserDbCommand.CommandText = textQuery;
deleteUserDbCommand.Parameters.Clear();
}
deleteUserDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, dbObject));
if (deleteUserDbCommand.ExecuteNonQuery() > 0)
{
primaryCounter++;
}
}
return (primaryCounter > 0);
}
///
/// Get membership and various information related to the user
///
///
///
///
///
///
///
///
public object GetMembershipByUserName(DbConnection conn, string parameterName, DbType dbType, object value, out bool authenticated, bool caseSensitive)
{
authenticated = false;
string textQuery = "SELECT userid, isanonymous FROM aspnet_users WHERE LOWER(applicationname) = :applicationname AND ";
if (caseSensitive)
{
textQuery = textQuery + parameterName + " = :" + parameterName;
}
else
{
textQuery = textQuery + "LOWER(" + parameterName + ") = :" + parameterName;
}
// Database command
IDbCommand selectUserDbCommand = this.CreateCommand(textQuery, conn);
selectUserDbCommand.Parameters.Add(this.CreateParameter("applicationname", DbType.String, 0xff, this.ApplicationName.ToLower()));
selectUserDbCommand.Parameters.Add(this.CreateParameter(parameterName, dbType, value));
object dbObj = null;
// Once the database connection is opened call the the reader to harvest data
IDataReader selectUserDataReader = null;
try
{
selectUserDataReader = selectUserDbCommand.ExecuteReader();
if (selectUserDataReader.Read())
{
dbObj = (Guid) this.ReadField(selectUserDataReader, 0, DbType.Guid);
authenticated = !selectUserDataReader.GetBoolean(1);
}
}
finally
{
if (selectUserDataReader != null)
{
selectUserDataReader.Close();
}
}
// The value that is returned
return dbObj;
}
///
/// Get user records for the database using the userID
///
///
///
///
///
private int GetRecordCount(DbConnection conn, string tableName, object userId)
{
IDbCommand getRecCountDbCommand = this.CreateCommand("SELECT COUNT(*) FROM " + tableName + " WHERE userid = :userid ", conn);
getRecCountDbCommand.Parameters.Add(this.CreateParameter("userid", DbType.Guid, userId));
IDataReader getRecCountDbreader = null;
try
{
getRecCountDbreader = getRecCountDbCommand.ExecuteReader();
if (getRecCountDbreader.Read())
{
return getRecCountDbreader.GetInt32(0);
}
}
catch (Exception exception)
{
throw exception;
}
finally
{
if (getRecCountDbreader != null)
{
getRecCountDbreader.Close();
}
}
return 0;
}
///
///
///
///
///
///
///
protected virtual object ReadField(IDataReader reader, int i, DbType dbType)
{
return reader.GetValue(i);
}
///
/// Update user information in the database
///
///
///
///
public Guid UpdateUser(DbConnection conn, MembershipUser user)
{
object objReturn = null;
bool flagValidate;
if (((objReturn = this.GetMembershipByUserName(conn, "username", DbType.String, user.UserName.ToLower(), out flagValidate, false)) == null) || ((user.ProviderUserKey != null) && (((Guid) objReturn) != ((Guid) user.ProviderUserKey))))
{
throw new ProviderException("User does not exist.");
}
IDbCommand updateUserDbCommand = this.CreateCommand("UPDATE aspnet_users SET lastactivitydate = :lastactivitydate WHERE LOWER(applicationname) = :applicationname AND LOWER(username) = :username", conn);
updateUserDbCommand.Parameters.Add(this.CreateParameter("lastactivitydate", DbType.DateTime, DateTime.Now));
updateUserDbCommand.Parameters.Add(this.CreateParameter("applicationname", DbType.String, 0xff, this.ApplicationName.ToLower()));
updateUserDbCommand.Parameters.Add(this.CreateParameter("username", DbType.String, 0xff, user.UserName.ToLower()));
updateUserDbCommand.ExecuteNonQuery();
return (Guid) objReturn;
}
///
/// Modify various user parameters in the pluggable membership datastore
///
///
///
///
public void UpdateUserParameter(string connectionString, string userName, params object[] parameters)
{
DbConnection updateUserParamConnection = this.provider.CreateConnection();
updateUserParamConnection.ConnectionString = connectionString;
string textQuery = "UPDATE aspnet_users SET ";
for (int i = 0; i < parameters.Length; i += 3)
{
textQuery = textQuery + ((string) parameters[i]) + " = :" + ((string) parameters[i]);
if ((i + 3) < parameters.Length)
{
textQuery = textQuery + ", ";
}
else
{
textQuery = textQuery + " ";
}
}
textQuery = textQuery + "WHERE LOWER(applicationname) = :applicationname AND LOWER(username) = :username";
IDbCommand caseUserParamDbCommand = this.CreateCommand(textQuery, updateUserParamConnection);
for (int ii = 0; ii < parameters.Length; ii += 3)
{
caseUserParamDbCommand.Parameters.Add(this.CreateParameter((string) parameters[ii], (DbType) parameters[ii + 1], parameters[ii + 2]));
}
caseUserParamDbCommand.Parameters.Add(this.CreateParameter("applicationname", DbType.String, 0xff, this.ApplicationName.ToLower()));
caseUserParamDbCommand.Parameters.Add(this.CreateParameter("username", DbType.String, 0xff, userName.ToLower()));
try
{
updateUserParamConnection.Open();
caseUserParamDbCommand.ExecuteNonQuery();
}
finally
{
updateUserParamConnection.Close();
}
}
}
}