Skip to main content

Overview

SMAF implements a comprehensive role-based access control (RBAC) system to manage permissions across different organizational levels. The permission system controls access to modules, features, and data based on user roles and hierarchical relationships.

Role-Based Access Control (RBAC)

Permission Entity Structure

The system manages permissions through the crip_permisos table with the following structure:
CREATE TABLE crip_permisos (
    CLV_USUARIO VARCHAR,      -- User ID
    PERMISO VARCHAR,          -- Permission code
    AUT_EXTERNO VARCHAR,      -- External authorizer
    CLV_PROY VARCHAR,         -- Project code
    CLV_DEP_PROY VARCHAR,     -- Project department
    ESTATUS VARCHAR,          -- Status (1=Active, 0=Inactive)
    FECHA DATE,               -- Permission date
    OBSERVACIONES TEXT,       -- Notes/observations
    CANTIDAD_PERMISOS INT     -- Number of permissions
)

Permission Levels and Roles

Organizational Hierarchy

The system defines a hierarchical permission structure based on roles:
1

Level 1: General Director

Role Code: DIRGRAINA
  • Highest authority level
  • System-wide access to all modules and data
  • Can authorize any request regardless of amount or type
  • Access to all departments and centers
2

Level 2: Adjunct Directors

Role Codes: DIRADJUNT, SUBDIRAD
  • Regional authority over assigned directorates
  • Can approve requests within their directorate
  • Access to all centers under their directorate
  • Budget oversight for their area
3

Level 3: Administrative Directors

Role Codes: DIRADMIN, ADMINP
  • Financial and administrative oversight
  • Budget management and approval authority
  • System configuration access
  • User management capabilities
4

Level 4: Center Chiefs

Role Code: JFCCRIPSC
  • Authority over specific research centers
  • Approval of requests from center personnel
  • Access to center-level reports and data
  • Budget management for their center
5

Level 5: Administrators

Role Code: ADMCRIPSC
  • Center-level administrative access
  • Process and validate expense requests
  • Generate reports for their center
  • User support and assistance
6

Level 6: Department Chiefs

Role Code: JFDEPTO
  • Department-level approval authority
  • Manage department personnel
  • Access to department reports
7

Level 7: Liaison Personnel

Role Code: ENLACE
  • Coordinate request processing
  • Data entry and validation
  • Limited approval authority
8

Level 8: Researchers

Role Code: INVEST
  • Create expense and travel requests
  • View own requests and reports
  • Submit documentation

Permission Types

The system defines specific permission codes for different operations:
VIAT
string
Travel Allowance (Viáticos)Permission to create and approve travel allowance requests. Date-based permission that must be renewed daily.
OFMAY
string
Major Official DocumentsPermission to generate official documents with certain thresholds. Date-based, requires daily renewal.
EXT
string
External AccessSpecial permission for external users or consultants. Requires daily authorization.
EXTPROY
string
External Project AccessPermission for external users to access specific projects. Date-based and project-specific.
ADML
string
Local AdministratorLocal administrative permissions for center-level management.
ADME
string
External AdministratorAdministrative permissions for external consultants or contractors.

Permission Validation

Check User Permission

The system validates permissions using the obtienePermisos method:
string obtienePermisos(string psUsuario, string psPermiso, 
                       string psProyecto = "", string psDep = "")
{
    string lsPermisos = "";
    string lsQuery = "SELECT PERMISO FROM crip_permisos " +
                     "WHERE CLV_USUARIO = '" + psUsuario + "' " +
                     "AND PERMISO = '" + psPermiso + "' " +
                     "AND ESTATUS = '1'";
    
    // Date-based permissions require current date validation
    if ((psPermiso == "VIAT") || (psPermiso == "OFMAY") || 
        (psPermiso == "EXT") || (psPermiso == "EXTPROY")) {
        lsQuery += "AND FECHA = '" + lsHoy + "'";
    }
    
    // Project-specific permissions
    if (psProyecto != "") {
        lsQuery += "AND CLV_PROY = '" + psProyecto + "'";
    }
    
    // Department-specific permissions
    if (psDep != "") {
        lsQuery += "AND CLV_DEP_PROY = '" + psDep + "'";
    }
    
    // Returns permission code if valid, empty string otherwise
}
Time-sensitive permissions (VIAT, OFMAY, EXT, EXTPROY) are validated against the current date. These permissions expire daily and must be renewed by an authorizer.

Count Active Permissions

Check how many active permissions a user has for a specific type:
int obtieneCountPermisos(string psUsuario, string psPermiso)
{
    int lsPermisos = 0;
    string lsQuery = "SELECT COUNT(*) AS COUNT FROM crip_permisos " +
                     "WHERE CLV_USUARIO = '" + psUsuario + "' " +
                     "AND FECHA = '" + lsHoy + "' " +
                     "AND ESTATUS = '1' " +
                     "AND PERMISO = '" + psPermiso + "'";
    
    // Returns count of active permissions for today
}

Get Permission Quantity

Retrieve the number of operations allowed under a permission:
int obtieneCantPermisos(string psUsuario, string psPermiso)
{
    string lsQuery = "SELECT CANTIDAD_PERMISOS FROM crip_permisos " +
                     "WHERE CLV_USUARIO = '" + psUsuario + "' " +
                     "AND FECHA = '" + lsHoy + "' " +
                     "AND ESTATUS = '1' " +
                     "AND PERMISO = '" + psPermiso + "'";
    
    // Returns quantity limit for the permission
}

Module Access Control

Department-Based Access

Users can only access data from their assigned department(s):
// Get users from specific department
List<Entidad> ListaUsuariosDependencia(string psDep)
{
    string lsQuery = "SELECT DISTINCT USSER AS CODIGO, " +
                     "CONCAT(NOMBRE,' ',APELLIDO_PAT,' ',APELLIDO_MAT) AS DESCRIPCION " +
                     "FROM vw_usuarios " +
                     "WHERE DEPENDENCIA = '" + psDep + "'";
}

Role-Based Data Filtering

The system uses role codes to filter accessible data:
string Obtiene_Usuario(string psRol, string psDep = "", string psCargo = "")
{
    string lsQuery = "SELECT DISTINCT(USUARIO) AS USUARIO " +
                     "FROM crip_job " +
                     "WHERE ROL = '" + psRol + "' ";
    
    if (psDep != "") {
        lsQuery += "AND CLV_DEP = '" + psDep + "'";
    }
    
    if (psCargo != "") {
        lsQuery += "AND CARGO = '" + psCargo + "'";
    }
    
    lsQuery += "AND ESTATUS = '1' " +
               "AND PERIODO = '" + lsYear + "'";
}

Hierarchical Permissions

VoBo (Approval) Authorization

The system implements a “VoBo” (Visto Bueno / Approval) workflow:
private string lsVobo = "VOBO";        // Approval role
private string lsAutoriza = "AUTORIZA"; // Authorizer role

public string VOBO
{
    get { return lsVobo; }
}

public string AUTORIZA
{
    get { return lsAutoriza; }
}

Approval Workflow

1

Request Creation

User with INVEST role creates an expense or travel request.
2

VoBo Review

Request is routed to the user’s supervisor or department chief for initial approval (VoBo).
3

Administrative Review

Administrator (ADMCRIPSC) validates the request against budget and policy.
4

Final Authorization

Center Chief (JFCCRIPSC) or higher authority provides final authorization.
5

Processing

Approved request is processed and payment/reimbursement is issued.

Permission Assignment Process

Creating New Permission

Grant a new permission to a user:
Boolean Insert_NuevoPermiso(string psUsuario, string psPermiso, 
                            string psAutoriza, string psFecha, 
                            string psObservaciones = "", 
                            string psCantPermisos = "")
{
    string lsQuery = "INSERT INTO crip_permisos " +
                     "(CLV_USUARIO, PERMISO, AUT_EXTERNO, CLV_PROY, " +
                     "CLV_DEP_PROY, ESTATUS, FECHA, OBSERVACIONES, " +
                     "CANTIDAD_PERMISOS) " +
                     "VALUES (" +
                     "'" + psUsuario + "', " +
                     "'" + psPermiso + "', " +
                     "'" + psAutoriza + "', " +
                     "'1', '1', '1', " +
                     "'" + clsFunciones.FormatFecha(psFecha) + "', " +
                     "'" + psObservaciones + "', " +
                     "'" + psCantPermisos + "')";
    
    // Execute insert and return success/failure
}
Permissions should only be granted by users with appropriate authorization levels. The psAutoriza parameter tracks who granted the permission for audit purposes.

Permission Parameters

psUsuario
string
required
User ID receiving the permission
psPermiso
string
required
Permission type code (VIAT, EXT, ADML, etc.)
psAutoriza
string
required
User ID of the person granting the permission
psFecha
string
required
Date the permission is valid for (format: YYYY-MM-DD)
psObservaciones
string
Optional notes or justification for the permission
psCantPermisos
string
Optional quantity limit for the permission

Permission Catalog

List Available Permissions

Retrieve all available permission types:
List<Entidad> ObtieneListPermisos()
{
    string lsQuery = "SELECT DISTINCT CLV_PERMISO AS CODIGO, " +
                     "CLV_PERMISO AS DESCRIPCION " +
                     "FROM crip_catalogo_permisos " +
                     "WHERE ESTATUS = '1'";
    
    // Returns list of active permission types
}

Organizational Unit Permissions

Directorate-Level Access

The system defines permissions for major organizational units:
DGAIA
string
Directorate General of Aquaculture Research and InnovationDepartment code: 2000Special permissions include access to aquaculture sub-directorate (SUBACUA).
DGAIPP
string
Directorate General of Fisheries Research in the PacificDepartment code: 4000
DGAIPA
string
Directorate General of Fisheries Research in the AtlanticDepartment code: 3000
DA
string
Directorate of AdministrationDepartment code: 5000Includes sub-directorates: Informatics (5100), Financial (5200), Materials (5300), Human Resources (5100)
DG
string
General DirectorateDepartment code: 1000Highest organizational level

Cross-Directorate Access

Some roles have special cross-directorate permissions:
if (psDep == Dictionary.DGAIA)
{
    lsQuery += "OR DEPENDENCIA = '" + Dictionary.SUBACUA + "'";
}
This allows DGAIA users to also access SUBACUA (Aquaculture Sub-directorate) data.

Request Limits and Quotas

Daily Request Limits

Check the number of requests submitted by a user today:
int obtieneCountSolicitudes(string psUsuario)
{
    string lsQuery = "SELECT COUNT(*) AS COUNT FROM crip_comision " +
                     "WHERE USUARIO = '" + psUsuario + "' " +
                     "AND FECHA_SOL = '" + lsHoy + "'";
    
    // Returns count of requests submitted today
}
This can be used to implement daily quotas or rate limiting for request submission.

Project-Specific Permissions

Permissions can be scoped to specific projects and project departments:
// Validate permission for specific project
string permisoProyecto = obtienePermisos(
    psUsuario: "JLOPEZ",
    psPermiso: "EXTPROY",
    psProyecto: "PROJ2024-001",
    psDep: "4000"
);

Security Best Practices

1

Validate permissions on every request

Always check user permissions before allowing access to sensitive operations or data.
2

Implement time-based expiration

Use date-based validation for temporary or elevated permissions.
3

Log permission grants and revocations

Maintain audit trail of who granted permissions and when.
4

Use least privilege principle

Grant only the minimum permissions necessary for users to perform their job functions.
5

Regular permission reviews

Periodically review and revoke unnecessary permissions, especially for inactive users.

Permission Validation Example

Complete example of validating and using permissions:
// Check if user has travel allowance permission
string hasViatPermission = MngDatosPermisos.obtienePermisos(
    psUsuario: Session["Usuario"].ToString(),
    psPermiso: "VIAT",
    psProyecto: "",
    psDep: Session["Ubicacion"].ToString()
);

if (hasViatPermission == "VIAT")
{
    // Check quantity limit
    int cantidadPermisos = MngDatosPermisos.obtieneCantPermisos(
        Session["Usuario"].ToString(),
        "VIAT"
    );
    
    // Check how many used today
    int solicitudesHoy = MngDatosPermisos.obtieneCountSolicitudes(
        Session["Usuario"].ToString()
    );
    
    if (solicitudesHoy < cantidadPermisos)
    {
        // User can create travel request
        // Proceed with request creation
    }
    else
    {
        // Quota exceeded
        ShowError("Daily travel request limit exceeded");
    }
}
else
{
    // No permission
    ShowError("You do not have permission to create travel requests");
}

Database Schema

Permission Tables

crip_permisos - Active permissions
  • Stores granted permissions with date and quantity limits
  • Status field for activation/deactivation
  • Links to user, project, and authorizer
crip_catalogo_permisos - Permission catalog
  • Master list of available permission types
  • Permission codes and descriptions
  • Active/inactive status
crip_job - User role assignments
  • Links users to roles and departments
  • Period-based for historical tracking
  • Status field for active assignments
vw_usuarios - User view with permissions
  • Consolidated view of users with role and department information
  • Filtered by active status and current period
  • Used for permission validation queries

Build docs developers (and LLMs) love