Click here to Skip to main content
15,896,359 members
Articles / Web Development / ASP.NET

Using Silverlight in Enterprise: RAD of User Friendly Database Access

Rate me:
Please Sign up or sign in to vote.
4.81/5 (19 votes)
31 Jul 2009CPOL8 min read 58.2K   7K   80  
This article introduces FulcrumWeb RAD Framework - A Silverlight UI Engine to build user friendly database driven applications
/********************************************************************
 *  FulcrumWeb RAD Framework - Fulcrum of your business             *
 *  Copyright (c) 2002-2009 FulcrumWeb, ALL RIGHTS RESERVED         *
 *                                                                  *
 *  THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      *
 *  FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        *
 *  COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       *
 *  AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  *
 *  AND PERMISSION FROM FULCRUMWEB. CONSULT THE END USER LICENSE    *
 *  AGREEMENT FOR INFORMATION ON ADDITIONAL RESTRICTIONS.           *
 ********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
using Framework.Db;
using Framework.Utils;

namespace Framework.Metadata
{
	/// <summary>
	/// Class containing permissions for the current user read from DB.
	/// </summary>
	public class CxUserPermissionProvider : IxUserPermissionProvider
	{
    //-------------------------------------------------------------------------
    // Database table names
    protected const string TABLE_USERS              = "Framework_Users";
    protected const string TABLE_ROLES              = "Framework_Roles";
    protected const string TABLE_USER_ROLES         = "Framework_UserRoles";
    protected const string TABLE_OBJECT_PERMISSIONS = "Framework_ObjectPermissions";
    //-------------------------------------------------------------------------
    protected const string COLUMN_OBJECT_PERMISSIONS_ROLE_ID = "RoleId";
    protected const string COLUMN_OBJECT_PERMISSIONS_USER_ID = "UserId";
    protected const string COLUMN_OBJECT_PERMISSIONS_OBJECT_ID = "ObjectId";
    protected const string COLUMN_OBJECT_PERMISSIONS_OBJECT_TYPE = "ObjectType";
    protected const string COLUMN_OBJECT_PERMISSIONS_PERMISSION_GROUP_ID = "PermissionGroupId";
    protected const string COLUMN_OBJECT_PERMISSIONS_PERMISSION_ID = "PermissionId";
    //-------------------------------------------------------------------------
    public const string SC_ADMINISTRATOR = "Administrator";
    //-------------------------------------------------------------------------
    protected CxMetadataHolder m_Holder = null;
    protected Dictionary<int, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> m_Data =
      new Dictionary<int, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>();
    protected string m_UserName = "";
    protected object m_RoleId = null;
    protected bool m_IsAdministrator = false;
    protected Dictionary<CxPermissionKey, string> m_Records = new Dictionary<CxPermissionKey, string>();
    //-------------------------------------------------------------------------
    public const string SYS_LOGIN = "Developer";
    public const string SYS_LOGIN_HASH = "4lE0lVAbYwFvXW+EIg73Cw==";
    //-------------------------------------------------------------------------
    /// <summary>
    /// Constructor.
    /// </summary>
		public CxUserPermissionProvider(CxMetadataHolder holder)
		{
      m_Holder = holder;
		}
    //-------------------------------------------------------------------------
    /// <summary>
    /// Adds permission to the list of available permissions.
    /// </summary>
    /// <param name="roleId">role ID</param>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    /// <param name="permissionId">ID of assigned permission option</param>
    protected void AddPermission(
      int roleId,
      string objectType,
      string objectId,
      string permissionGroupId,
      string permissionId)
    {
      if (roleId < 0 ||
          String.IsNullOrEmpty(objectType) ||
          String.IsNullOrEmpty(objectId) ||
          String.IsNullOrEmpty(permissionGroupId) ||
          String.IsNullOrEmpty(permissionId))
      {
        return;
      }
      objectType = CxText.ToUpper(objectType);
      objectId = CxText.ToUpper(objectId);
      permissionGroupId = CxText.ToUpper(permissionGroupId);
      permissionId = CxText.ToUpper(permissionId);
      string currentId = GetPermissionRuleId(roleId, objectType, objectId, permissionGroupId);
      int curIndex = Holder.Security.GetIndexOfRule(currentId);
      int newIndex = Holder.Security.GetIndexOfRule(permissionId);
      bool addPermission = newIndex >= 0;
      if (addPermission && curIndex >= 0 && newIndex > curIndex)
      {
        addPermission = false;
      }
      if (!addPermission)
      {
        return;
      }
      Dictionary<string, Dictionary<string, Dictionary<string, string>>> objectTypes;
      if (!m_Data.TryGetValue(roleId, out objectTypes))
      {
        objectTypes = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
        m_Data.Add(roleId, objectTypes);
      }
      Dictionary<string, Dictionary<string, string>> objects;
      if (!objectTypes.TryGetValue(objectType, out objects))
      {
        objects = new Dictionary<string, Dictionary<string, string>>();
        objectTypes.Add(objectType, objects);
      }
      Dictionary<string, string> permissionGroups;
      if (!objects.TryGetValue(objectId, out permissionGroups))
      {
        permissionGroups = new Dictionary<string, string>();
        objects.Add(objectId, permissionGroups);
      }
      permissionGroups[permissionGroupId] = permissionId;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission ID for the given metadata object and permission group.
    /// </summary>
    /// <param name="roleId">role ID</param>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    protected string GetPermissionId(
      int roleId,
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      if (String.IsNullOrEmpty(objectType) ||
          String.IsNullOrEmpty(objectId) ||
          String.IsNullOrEmpty(permissionGroupId))
      {
        return null;
      }
      objectType = CxText.ToUpper(objectType);
      objectId = CxText.ToUpper(objectId);
      permissionGroupId = CxText.ToUpper(permissionGroupId);
      Dictionary<string, Dictionary<string, Dictionary<string, string>>> objectTypes;
      if (!m_Data.TryGetValue(roleId, out objectTypes))
      {
        return null;
      }
      Dictionary<string, Dictionary<string, string>> objects;
      if (!objectTypes.TryGetValue(objectType, out objects))
      {
        return null;
      }
      Dictionary<string, string> permissionGroups;
      if (!objects.TryGetValue(objectId, out permissionGroups))
      {
        return null;
      }
      string permissionId;
      if (!permissionGroups.TryGetValue(permissionGroupId, out permissionId))
      {
        return null;
      }
      return permissionId;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission ID for the given metadata object and permission group.
    /// </summary>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    protected string GetPermissionId(
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      string maxPermissionId = null;
      int minPermissionIndex = Int32.MaxValue;
      foreach (int roleId in m_Data.Keys)
      {
        CxPermission permission = GetPermission(roleId, objectType, objectId, permissionGroupId);
        if (permission == null && 
            GetIsCustomPermissionChild(roleId, objectType, objectId, permissionGroupId))
        {
          // Bug fix. For the command or attribute permissions which are children of an entity 
          // with custom permission we must take default permission if permission is not set.
          CxSecurityObject securityObject = Holder.Security.GetSecurityObject(objectType);
          if (securityObject != null)
          {
            CxPermissionGroup group = securityObject.GetPermissionGroup(permissionGroupId);
            if (group != null)
            {
              permission = group.DefaultPermission;
            }
          }
        }
        if (permission != null)
        {
          int index = Holder.Security.GetIndexOfRule(permission.RuleId);
          if (index >= 0 && index < minPermissionIndex)
          {
            maxPermissionId = permission.Id;
            minPermissionIndex = index;
          }
        }
      }
      return maxPermissionId;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns true if given permission is a child of entity which have Custom permission.
    /// Such children are command permissions and attribute permissions.
    /// </summary>
    /// <param name="roleId"></param>
    /// <param name="objectType"></param>
    /// <param name="objectId"></param>
    /// <param name="permissionGroupId"></param>
    /// <returns></returns>
    protected bool GetIsCustomPermissionChild(
      int roleId,
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      if (!CxSecurityMetadata.TYPE_COMMAND.Equals(objectType, StringComparison.OrdinalIgnoreCase) &&
          !CxSecurityMetadata.TYPE_ATTRIBUTE.Equals(objectType, StringComparison.OrdinalIgnoreCase))
      {
        return false;
      }

      // Get entity ID and command/attribute ID from the compound security object ID.
      string entityId;
      string childObjectId;
      Holder.Security.SplitObjectId(objectType, objectId, out childObjectId, out entityId);
      if (String.IsNullOrEmpty(entityId))
      {
        return false;
      }

      // Get metadata object.
      CxMetadataObject metadataObject = null;
      if (CxSecurityMetadata.TYPE_COMMAND.Equals(objectType, StringComparison.OrdinalIgnoreCase))
      {
        metadataObject = Holder.Commands.Find(childObjectId);
      }
      else if (CxSecurityMetadata.TYPE_ATTRIBUTE.Equals(objectType, StringComparison.OrdinalIgnoreCase))
      {
        CxEntityMetadata entityMetadata = Holder.EntityUsages.Find(entityId);
        if (entityMetadata == null)
        {
          entityMetadata = Holder.Entities.Find(entityId);
        }
        if (entityMetadata != null)
        {
          metadataObject = entityMetadata.GetAttribute(childObjectId);
        }
      }

      // Get entity permission group by the metadata object.
      CxSecurityObject securityObject = Holder.Security.GetSecurityObject(objectType);
      CxEntityGroup entityGroup = null;
      if (metadataObject != null)
      {
        entityGroup = securityObject.GetEntityGroup(metadataObject);
      }
      else if (securityObject.EntityGroups.Count > 0)
      {
        entityGroup = securityObject.EntityGroups[0];
      }
      if (entityGroup == null)
      {
        return false;
      }

      // Get entity permission for the related permission group.
      CxPermission entityPermission = GetPermission(
        roleId, CxSecurityMetadata.TYPE_ENTITY, entityId, entityGroup.Id);

      return entityPermission != null && 
             entityPermission.Rule != null && 
             entityPermission.Rule.IsCustomRule;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission object for the given metadata object and permission group.
    /// </summary>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    /// <param name="permissionId">ID of permission</param>
    protected CxPermission GetPermission(
      string objectType,
      string objectId,
      string permissionGroupId,
      string permissionId)
    {
      if (CxUtils.NotEmpty(permissionId))
      {
        CxSecurityObject securityObject = Holder.Security.GetSecurityObject(objectType);
        if (securityObject != null)
        {
          CxPermissionGroup group = securityObject.GetPermissionGroup(permissionGroupId);
          if (group != null)
          {
            return group.GetPermission(permissionId);
          }
        }
      }
      return null;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission object for the given metadata object and permission group.
    /// </summary>
    /// <param name="roleId">role ID</param>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    protected CxPermission GetPermission(
      int roleId,
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      string permissionId = GetPermissionId(roleId, objectType, objectId, permissionGroupId);
      return GetPermission(objectType, objectId, permissionGroupId, permissionId);
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission object for the given metadata object and permission group.
    /// </summary>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    virtual public CxPermission GetPermission(
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      if (IsDevelopmentMode || IsAdministrator)
      {
        return Holder.Security.GetAllowPermission(objectType, objectId, permissionGroupId);
      }
      string permissionId = GetPermissionId(objectType, objectId, permissionGroupId);
      return GetPermission(objectType, objectId, permissionGroupId, permissionId);
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns rule ID for the given metadata object and permission group.
    /// </summary>
    /// <param name="roleId">role ID</param>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    protected string GetPermissionRuleId(
      int roleId,
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      CxPermission permission = GetPermission(roleId, objectType, objectId, permissionGroupId);
      return permission != null ? permission.RuleId : null;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns permission rule object (if specified).
    /// </summary>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    virtual public CxPermissionRule GetRule(
      string objectType,
      string objectId,
      string permissionGroupId)
    {
      if (IsDevelopmentMode || IsAdministrator)
      {
        return Holder.Security.AllowRule;
      }
      CxPermission permission = GetPermission(objectType, objectId, permissionGroupId);
      return permission != null ? permission.Rule : null;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Clears all loaded permissions.
    /// </summary>
    protected void Clear()
    {
      m_Data.Clear();
      m_Records.Clear();
      m_UserName = "";
      m_RoleId = null;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Loads user permissions list from database.
    /// </summary>
    /// <param name="connection">DB connection to load permissions from</param>
    /// <param name="userName">current user name</param>
    virtual public void LoadUser(CxDbConnection connection, string userName)
    {
      Clear();
      m_IsAdministrator = false;
      if (CxUtils.NotEmpty(userName))
      {
        if (userName != SYS_LOGIN)
        {
          string sql =
            "SELECT op.* " +
            "  FROM " + TABLE_OBJECT_PERMISSIONS + " op, " +
            "       " + TABLE_ROLES + " r, " +
            "       " + TABLE_USER_ROLES + " ur, " +
            "       " + TABLE_USERS + " u " +
            " WHERE op.RoleId = r.RoleId " +
            "   AND r.RoleId = ur.RoleId " +
            "   AND ur.UserId = u.UserId " +
            "   AND u.Login = :Login ";

          DataTable dt = connection.GetQueryResult(sql, userName);

          UniqueList<int> roles = new UniqueList<int>();
          foreach (DataRow row in dt.Rows)
          {
            AddPermission(
              CxInt.Parse(row[COLUMN_OBJECT_PERMISSIONS_ROLE_ID], -1),
              row[COLUMN_OBJECT_PERMISSIONS_OBJECT_TYPE].ToString(),
              row[COLUMN_OBJECT_PERMISSIONS_OBJECT_ID].ToString(),
              row[COLUMN_OBJECT_PERMISSIONS_PERMISSION_GROUP_ID].ToString(),
              row[COLUMN_OBJECT_PERMISSIONS_PERMISSION_ID].ToString());

            m_Records[new CxPermissionKey(row)] = row[COLUMN_OBJECT_PERMISSIONS_PERMISSION_ID].ToString();
            roles.Add(CxInt.Parse(row[COLUMN_OBJECT_PERMISSIONS_ROLE_ID], 0));
          }

          sql =
            @"SELECT COUNT(1) AS RecCount
                FROM " + TABLE_ROLES + @" r,
                     " + TABLE_USER_ROLES + @" ur,
                     " + TABLE_USERS + @" u
               WHERE r.RoleId = ur.RoleId 
                 AND ur.UserId = u.UserId 
                 AND u.Login = :Login 
                 AND r.SpecialCategory = :SpecialCategory";
          int count =
            CxInt.Parse(connection.ExecuteScalar(sql, userName, SC_ADMINISTRATOR), 0);
          if (count > 0)
          {
            m_IsAdministrator = true;
          }

          m_UserName = userName;

          // Add entity permissions provided by subsystems
          IList<string> subsystems = Holder.GetEntityGroupNameList();
          IList<CxEntityMetadata> entities = Holder.Security.GetSecurityEntityList();
          CxSecurityObject securityObject = Holder.Security.GetSecurityObject(CxSecurityMetadata.TYPE_ENTITY);
          foreach (string subsystem in subsystems)
          {
            foreach (CxEntityMetadata entity in entities)
            {
              if (entity.GroupName == subsystem)
              {
                foreach (CxPermissionGroup group in securityObject.PermissionGroups)
                {
                  foreach (int roleId in roles)
                  {
                    CxPermissionKey entityKey =
                      new CxPermissionKey(entity.Id, CxSecurityMetadata.TYPE_ENTITY, group.Id, roleId);
                    CxPermissionKey subsystemKey =
                      new CxPermissionKey(subsystem, CxSecurityMetadata.TYPE_SUBSYSTEM, group.Id, roleId);
                    if (!m_Records.ContainsKey(entityKey))
                    {
                      string permissionId;
                      if (m_Records.TryGetValue(subsystemKey, out permissionId))
                      {
                        AddPermission(roleId, CxSecurityMetadata.TYPE_ENTITY, entity.Id, group.Id, permissionId);
                      }
                    }
                  }
                }
              }
            }
          }
        }
        else
        {
          // For Developer user
          m_UserName = userName;
        }
      }
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Loads role permissions list from database.
    /// </summary>
    /// <param name="connection">DB connection to load permissions from</param>
    /// <param name="roleId">role ID</param>
    virtual public void LoadRole(CxDbConnection connection, object roleId)
    {
      Clear();
      m_IsAdministrator = false;
      if (CxUtils.NotEmpty(roleId))
      {
        string sql =
          "SELECT op.* " +
          "  FROM " + TABLE_OBJECT_PERMISSIONS + " op " +
          " WHERE op.RoleId = :RoleId ";

        DataTable dt = connection.GetQueryResult(sql, roleId);
        foreach (DataRow row in dt.Rows)
        {
          AddPermission(
            CxInt.Parse(roleId, -1),
            row[COLUMN_OBJECT_PERMISSIONS_OBJECT_TYPE].ToString(),
            row[COLUMN_OBJECT_PERMISSIONS_OBJECT_ID].ToString(),
            row[COLUMN_OBJECT_PERMISSIONS_PERMISSION_GROUP_ID].ToString(),
            row[COLUMN_OBJECT_PERMISSIONS_PERMISSION_ID].ToString());
        }

        sql = 
          @"SELECT COUNT(1) AS RecCount
                FROM " + TABLE_ROLES + @" r
               WHERE r.RoleId = :RoleId 
                 AND r.SpecialCategory = :SpecialCategory";
        int count = 
          CxInt.Parse(connection.ExecuteScalar(sql, roleId, SC_ADMINISTRATOR), 0);
        if (count > 0)
        {
          m_IsAdministrator = true;
        }

        m_RoleId = roleId;
      }
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns true if given permission is default for the given metadata object.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="roleId">ID of role to check permission for</param>
    /// <param name="metadataObject">metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    /// <param name="permissionId">ID of permission</param>
    protected NxBoolEx GetIsPermissionDefault(
      CxDbConnection connection,
      object roleId,
      CxMetadataObject metadataObject,
      string permissionGroupId,
      string permissionId)
    {
      if (metadataObject is CxEntityMetadata)
      {
        CxEntityMetadata entity = (CxEntityMetadata) metadataObject;
        if (CxUtils.NotEmpty(entity.GroupName))
        {
          string sql = 
            @"select top 1 op.PermissionId
                from " + TABLE_OBJECT_PERMISSIONS + @" op
               where op.ObjectType = :ObjectType
                 and op.ObjectId = :ObjectId
                 and op.PermissionGroupId = :PermissionGroupId
                 and op.RoleId = :RoleId";

          string subsystemPermissionId = CxUtils.ToString(
            connection.ExecuteScalar(
              sql, 
              CxSecurityMetadata.TYPE_SUBSYSTEM, 
              entity.GroupName, 
              permissionGroupId, 
              roleId));

          if (CxUtils.NotEmpty(subsystemPermissionId))
          {
            return CxBoolEx.GetBoolEx(subsystemPermissionId == permissionId);
          }
        }
      }
      return NxBoolEx.Undefined;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Sets permission option for the given metadata object and permission group.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="roleId">ID of role to set permission for</param>
    /// <param name="metadataObject">metadata object</param>
    /// <param name="objectType">type of metadata object (entity, attribute, etc.)</param>
    /// <param name="objectId">ID of metadata object</param>
    /// <param name="permissionGroupId">ID of permission group</param>
    /// <param name="permissionGroupId">ID of permission option</param>
    /// <param name="permissionId">permission id</param>
    virtual public void SetPermission(
      CxDbConnection connection,
      object roleId,
      CxMetadataObject metadataObject,
      string objectType,
      string objectId,
      string permissionGroupId,
      string permissionId)
    {
      if (CxUtils.NotEmpty(permissionId))
      {
        CxSecurityObject securityObject = Holder.Security.GetSecurityObject(objectType);
        if (securityObject != null)
        {
          CxPermissionGroup group = securityObject.GetPermissionGroup(permissionGroupId);
          if (group != null)
          {
            CxPermission permission = group.GetPermission(permissionId);
            if (permission != null)
            {
              string checkSql = 
                @"SELECT COUNT(*) AS RoleCount
                    FROM " + TABLE_ROLES + @"
                   WHERE RoleId = :RoleId 
                     AND SpecialCategory = :SpecialCategory";
              int result = 
                CxInt.Parse(connection.ExecuteScalar(checkSql, roleId, SC_ADMINISTRATOR), 0);
              if (result > 0)
              {
                throw new ExException(Holder.GetErr("Administrator role permissions could not be changed."));
              }

              bool ownsTransaction = !connection.InTransaction;
              if (ownsTransaction)
              {
                connection.BeginTransaction();
              }
              try
              {
                string deleteSql = 
                  "DELETE FROM " + TABLE_OBJECT_PERMISSIONS +
                  " WHERE RoleId = :RoleId " +
                  "   AND ObjectType = :ObjectType " +
                  "   AND ObjectId = :ObjectId " +
                  "   AND PermissionGroupId = :PermissionGroupId";
                connection.ExecuteCommand(
                  deleteSql, roleId, objectType.ToUpper(), objectId, permissionGroupId);

                NxBoolEx isDefault = GetIsPermissionDefault(
                  connection, roleId, metadataObject, permissionGroupId, permissionId);
                if (isDefault == NxBoolEx.Undefined)
                {
                  isDefault = CxBoolEx.GetBoolEx(permission.IsDefault);
                }
                if (isDefault == NxBoolEx.False)
                {
                  string insertSql =
                    "INSERT INTO " + TABLE_OBJECT_PERMISSIONS +
                    "       (RoleId, ObjectType, ObjectId, PermissionGroupId, PermissionId) " +
                    "VALUES (:RoleId, :ObjectType, :ObjectId, :PermissionGroupId, :PermissionId)";
                  connection.ExecuteCommand(
                    insertSql, roleId, objectType.ToUpper(), objectId, permissionGroupId, permissionId);
                }
                if (ownsTransaction)
                {
                  connection.Commit();
                }
              }
              catch
              {
                if (ownsTransaction)
                {
                  connection.Rollback();
                }
                throw;
              }
            }
          }
        }
      }
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Validates user login and password.
    /// Raises exception if login or password is invalid.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userName">user name (login)</param>
    /// <param name="password">password</param>
    /// <param name="validatePassword">if false, user password will be not validated</param>
    virtual public void ValidateLogin(
      CxDbConnection connection, 
      string userName, 
      string password,
      bool validatePassword)
    {
      if (CxUtils.IsEmpty(userName))
      {
        throw new ExValidationException(Holder.GetErr("User name could not be empty."));
      }
      if (validatePassword && CxUtils.IsEmpty(password))
      {
        throw new ExValidationException(Holder.GetErr("Password could not be empty."));
      }

      if (userName == SYS_LOGIN)
      {
        if (validatePassword && CxCommon.ComputeMD5Hash(password) != SYS_LOGIN_HASH)
        {
          throw new ExValidationException(Holder.GetErr("Invalid password."));
        }
        return;
      }

      string sql =
        "SELECT u.Login, " +
        "       u.Password, " +
        "       u.IsDeactivated, " +
        "       u.DeactivatedDate, " +
        "       (SELECT COUNT(*) " +
        "          FROM " + TABLE_USER_ROLES + " ur " +
        "         WHERE u.UserId = ur.UserId) AS RoleCount " +
        "  FROM " + TABLE_USERS + " u " +
        " WHERE u.Login = :Login";
      DataTable dt = connection.GetQueryResult(sql, userName);
      if (dt.Rows.Count == 0)
      {
        throw new ExValidationException(Holder.GetErr("User name is invalid."));
      }
      else if (dt.Rows.Count > 1)
      {
        throw new ExValidationException(Holder.GetErr("User name is not unique."));
      }

      if (validatePassword &&
          CxCommon.ComputeMD5Hash(password) != dt.Rows[0]["Password"].ToString())
      {
        throw new ExValidationException(Holder.GetErr("Invalid password."));
      }

      if (CxBool.Parse(dt.Rows[0]["IsDeactivated"]))
      {
        throw new ExValidationException(Holder.GetErr("User name is deactivated."));
      }
      if (CxUtils.IsEmpty(dt.Rows[0]["RoleCount"]) ||
        (int) dt.Rows[0]["RoleCount"] == 0)
      {
        throw new ExValidationException(Holder.GetErr("User does not have roles."));
      }
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns user ID for the given user name (login).
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userName">user name (login)</param>
    virtual public object GetUserId(
      CxDbConnection connection,
      string userName)
    {
      if (userName == SYS_LOGIN)
      {
        return 0;
      }
      string sql =
        "SELECT UserId FROM " + TABLE_USERS + 
        " WHERE Login = :Login";
      object userId = connection.ExecuteScalar(sql, userName);
      return userId;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns framework user ID for the given user name (login).
    /// Framework user ID means user ID stored in the Framework_Users table.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userName">user name (login)</param>
    virtual public object GetFrameworkUserId(CxDbConnection connection, string userName)
    {
      return GetUserId(connection, userName);
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Gets user's assigned role IDs.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">an ID of a user</param>
    /// <returns>an array of role IDs</returns>
    virtual public object[] GetUserRoles(
      CxDbConnection connection,
      object userId)
    {
      string selectSql =
        "select RoleId " +
        "  from " + TABLE_USER_ROLES +
        " where UserId = :UserId";
      DataTable dt = new DataTable();
      connection.GetQueryResult(dt, selectSql, userId);
      object[] roleIds = new object[dt.Rows.Count];
      for (int i = 0; i < dt.Rows.Count; i++)
      {
        DataRow row = dt.Rows[i];
        roleIds[i] = row[0];
      }
      return roleIds;
    }
	  //-------------------------------------------------------------------------
    /// <summary>
    /// Assigns roles to user.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    /// <param name="roleIdArray">array of Role IDs</param>
    virtual public void AssignUserRoles(
      CxDbConnection connection,
      object userId,
      object[] roleIdArray)
    {
      string checkSql =
        "SELECT COUNT(*) " +
        "  FROM " + TABLE_USER_ROLES + 
        " WHERE UserId = :UserId " +
        "   AND RoleId = :RoleId";
      string insertSql =
        "INSERT INTO " + TABLE_USER_ROLES + " (UserId, RoleId) " +
        "VALUES (:UserId, :RoleId)";
      connection.BeginTransaction();
      try
      {
        foreach (object roleId in roleIdArray)
        {
          object result = connection.ExecuteScalar(checkSql, userId, roleId);
          if (result is int && (int)result > 0)
          {
            continue;
          }
          connection.ExecuteCommand(insertSql, userId, roleId);
        }
        connection.Commit();
      }
      catch
      {
        connection.Rollback();
        throw;
      }
    }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Removes roles from user.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    /// <param name="roleIdArray">array of Role IDs</param>
    virtual public void RemoveUserRoles(
      CxDbConnection connection,
      object userId,
      object[] roleIdArray)
    {
      string deleteSql =
        "DELETE FROM " + TABLE_USER_ROLES + 
        " WHERE UserId = :UserId AND RoleId = :RoleId";
      connection.BeginTransaction();
      try
      {
        foreach (object roleId in roleIdArray)
        {
          connection.ExecuteCommand(deleteSql, userId, roleId);
        }
        connection.Commit();
      }
      catch
      {
        connection.Rollback();
        throw;
      }
    }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Marks user as active.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    virtual public void ActivateUser(CxDbConnection connection, object userId)
    {
      string sql =
        "UPDATE " + TABLE_USERS + 
        "   SET IsDeactivated = NULL, DeactivatedDate = NULL " +
        " WHERE UserId = :UserId";
      connection.ExecuteCommand(sql, userId);
    }
    //----------------------------------------------------------------------------
    /// <summary>
    /// Marks user as inactive.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    virtual public void DeactivateUser(CxDbConnection connection, object userId)
    {
      string sql =
        "UPDATE " + TABLE_USERS + 
        "   SET IsDeactivated = 1, DeactivatedDate = GETDATE() " +
        " WHERE UserId = :UserId " +
        "   AND (IsDeactivated = 0 OR IsDeactivated IS NULL)";
      connection.ExecuteCommand(sql, userId);
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns true if application is in development mode (security is not applied).
    /// </summary>
    virtual protected bool GetIsDevelopmentMode()
    {
      return m_UserName == SYS_LOGIN;
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Validates DB user name before insert or update.
    /// </summary>
    /// <param name="userName">user name to validate</param>
    virtual public void ValidateDbUserName(string userName)
    {
      if (CxText.Equals(userName, SYS_LOGIN))
      {
        throw new ExValidationException(
          Holder.GetErr("This user name is reserved for internal system purposes.\r\nPlease try another user name."));
      }
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns user info parameter value.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    /// <param name="paramName">name of parameter to get from user info</param>
    virtual public string GetUserInfo(
      CxDbConnection connection, 
      object userId, 
      string paramName)
    {
      string sql = 
        "select " + paramName + " from " + TABLE_USERS + " where UserId = :UserId";
      return CxUtils.ToString(connection.ExecuteScalar(sql, userId));
    }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns table of available workspaces for the given user.
    /// </summary>
    /// <param name="connection">database connection</param>
    /// <param name="userId">ID of user</param>
    virtual public DataTable GetAvailableWorkspaces(CxDbConnection connection, object userId)
    {
      DataTable dt;
      string sql;
      if (!IsDevelopmentMode)
      {
        sql = 
          @"select distinct 
                 w.WorkspaceId, 
                 w.Name,
                 w.Code,
                 w.Priority,
                 case 
                   when u.DefaultWorkspaceId = w.WorkspaceId
                   then 0
                   else 1
                 end as DefaultOrder
            from Framework_UserRoles ur
           inner join Framework_RoleWorkspaces rw
              on ur.RoleId = rw.RoleId
           inner join Framework_Workspaces w
              on rw.WorkspaceId = w.WorkspaceId
           inner join Framework_Users u
              on ur.UserId = u.UserId
           where ur.UserId = :UserId
             and w.WorkspaceId > 0
             and w.IsAvailable = 1

           union
           select 
                 w.WorkspaceId, 
                 w.Name,
                 w.Code,
                 w.Priority,
                 0 as DefaultOrder
           from Framework_Workspaces w
           inner join Framework_Users u
              on u.DefaultWorkspaceId = w.WorkspaceId
           where u.UserId = :UserId
             and w.WorkspaceId > 0
             and w.IsAvailable = 1

           order by 5, 4";
        dt = connection.GetQueryResult(sql, userId);
      }
      else
      {
        sql = 
          @"select w.WorkspaceId, 
                   w.Name,
                   w.Code,
                   w.Priority,
                   0 as DefaultOrder
              from Framework_Workspaces w
             where w.WorkspaceId > 0
               and w.IsAvailable = 1
             order by w.Priority";
        dt = connection.GetQueryResult(sql);
      }
      return dt;
    }
    //-------------------------------------------------------------------------

    //-------------------------------------------------------------------------
    /// <summary>
    /// Parent metadata holder object.
    /// </summary>
    public CxMetadataHolder Holder
    { get {return m_Holder;} }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns user name whose permissions were loaded.
    /// </summary>
    public string UserName
    { get {return m_UserName;} }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns role ID which permissions were loaded.
    /// </summary>
    public object RoleId
    { get {return m_RoleId;} }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns true if application is in development mode (security is not applied).
    /// </summary>
    public bool IsDevelopmentMode
    { get {return GetIsDevelopmentMode();} }
    //-------------------------------------------------------------------------
    /// <summary>
    /// Returns true if logged user is an administrator user.
    /// </summary>
    virtual public bool IsAdministrator
    { get {return m_IsAdministrator;} }
    //-------------------------------------------------------------------------

    //-------------------------------------------------------------------------
    protected class CxPermissionKey : IComparable, IEquatable<CxPermissionKey>
    {
      private string m_ObjectId;
      private string m_ObjectType;
      private string m_PermissionGroupId;
      private int m_RoleId;

      //-----------------------------------------------------------------------
      /// <summary>
      /// Constructor.
      /// </summary>
      /// <param name="objectId"></param>
      /// <param name="objectType"></param>
      /// <param name="permissionGroupId"></param>
      /// <param name="roleId"></param>
      public CxPermissionKey(
        string objectId,
        string objectType,
        string permissionGroupId,
        int roleId)
      {
        m_ObjectId = objectId;
        m_ObjectType = objectType;
        m_PermissionGroupId = permissionGroupId;
        m_RoleId = roleId;
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Constructor.
      /// </summary>
      /// <param name="dr">data row</param>
      public CxPermissionKey(DataRow dr)
      {
        m_ObjectId = dr["ObjectId"].ToString();
        m_ObjectType = dr["ObjectType"].ToString();
        m_PermissionGroupId = dr["PermissionGroupId"].ToString();
        m_RoleId = CxInt.Parse(dr["RoleId"], 0);
      }
      //-----------------------------------------------------------------------
      ///<summary>
      ///Compares the current instance with another object of the same type.
      ///</summary>
      ///
      ///<returns>
      ///A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than obj. Zero This instance is equal to obj. Greater than zero This instance is greater than obj. 
      ///</returns>
      ///
      ///<param name="obj">An object to compare with this instance. </param>
      ///<exception cref="T:System.ArgumentException">obj is not the same type as this instance. </exception><filterpriority>2</filterpriority>
      public int CompareTo(object obj)
      {
        CxPermissionKey key = obj as CxPermissionKey;
        if (key != null)
        {
          if (ObjectId.Equals(key.ObjectId, StringComparison.OrdinalIgnoreCase) &&
              ObjectType.Equals(key.ObjectType, StringComparison.OrdinalIgnoreCase) &&
              PermissionGroupId.Equals(key.PermissionGroupId, StringComparison.OrdinalIgnoreCase) &&
              RoleId == key.RoleId)
          {
            return 0;
          }
          else
          {
            return ObjectId.CompareTo(key.ObjectId);
          }
        }
        return 1;
      }
      //-----------------------------------------------------------------------
      ///<summary>
      ///Indicates whether the current object is equal to another object of the same type.
      ///</summary>
      ///
      ///<returns>
      ///true if the current object is equal to the other parameter; otherwise, false.
      ///</returns>
      ///
      ///<param name="other">An object to compare with this object.</param>
      public bool Equals(CxPermissionKey other)
      {
        return CompareTo(other) == 0;
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Retruns true if objects are equal.
      /// </summary>
      /// <param name="obj">object to compare</param>
      /// <returns>true if objects are equal</returns>
      public override bool Equals(object obj)
      {
        return Equals(obj as CxPermissionKey);
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Returns object hash code.
      /// </summary>
      /// <returns>hash code</returns>
      public override int GetHashCode()
      {
        string text = String.Format(
          "ObjectId:{0};ObjectType:{1};PermissionGroupId:{2};RoleId:{3}",
          ObjectId.ToUpper(), ObjectType.ToUpper(), PermissionGroupId.ToUpper(), RoleId);
        return text.GetHashCode();
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Object ID
      /// </summary>
      public string ObjectId
      {
        get { return m_ObjectId; }
        set { m_ObjectId = value; }
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Object type
      /// </summary>
      public string ObjectType
      {
        get { return m_ObjectType; }
        set { m_ObjectType = value; }
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Permission Group ID
      /// </summary>
      public string PermissionGroupId
      {
        get { return m_PermissionGroupId; }
        set { m_PermissionGroupId = value; }
      }
      //-----------------------------------------------------------------------
      /// <summary>
      /// Role ID
      /// </summary>
      public int RoleId
      {
        get { return m_RoleId; }
        set { m_RoleId = value; }
      }
    }
    //-------------------------------------------------------------------------
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions