Desarrollo de Scripts Personalizados para Tablas de Aplicaciones de Base de Datos (MSSQL) con Groovy

Visión General de Scripts Personalizados para Tablas de Aplicación de Base de Datos (MSSQL)

Al aprovisionar cuentas desde Oracle Access Governance mediante la integración de tablas de aplicación de base de datos, las operaciones como crear, actualizar y suprimir se implantan mediante el código proporcionado por defecto. En las ocasiones en las que desee modificar las operaciones proporcionadas por defecto, puede proporcionar opcionalmente sus propios scripts personalizados que implanten sus propios requisitos de operación de aprovisionamiento específicos. Este paso es completamente opcional, no tiene que crear scripts personalizados si las operaciones por defecto le proporcionan lo que necesita. Puede agregar scripts personalizados a cualquier operación admitida. Si selecciona scripts personalizados, solo tendrá que agregarlos cuando necesite que se modifique la operación por defecto, puede tener una combinación de scripts personalizados y por defecto para las operaciones soportadas, aunque solo puede tener una u otra opción para cada operación específica. Por ejemplo, la operación de creación se puede implantar con un script personalizado que agrega alguna funcionalidad específica a su organización, mientras que la operación de supresión no cambia y utiliza la funcionalidad por defecto.

Una vez que haya implantado y configurado las tablas de aplicación de base de datos para que utilicen un script personalizado, ese script se utilizará la siguiente vez que realice una operación de aprovisionamiento o carga de datos.
Nota

Cualquier script personalizado se debe implantar con formato Groovy. No se admiten otros formatos de secuencias de comandos.
Al crear un sistema orquestado de tablas de aplicación de base de datos, puede identificar los scripts que se van a ejecutar para una serie de operaciones de aprovisionamiento en la aplicación de base de datos que contienen datos de cuenta. Estas operaciones son:
  • Crear
  • Actualizar
  • Suprimir
  • Carga de datos
  • Agregar Datos de Relación
  • Eliminar Datos de Relación
Estos scripts se deben ubicar en el host del agente, en el directorio de instalación del agente, por ejemplo, /app/<custom script> . El agente se configura con la ubicación de los scripts en los valores de integración del sistema orquestado. Debe asegurarse de que el usuario del sistema operativo que ejecuta el agente tenga permisos de lectura/escritura para cualquier script personalizado.
Al realizar una tarea de aprovisionamiento, el script se ejecutará como una sustitución del procesamiento estándar asociado a la tarea. El script debe manejar la tarea de aprovisionamiento por defecto, como crear o actualizar, y también puede tener tareas personalizadas más allá del proceso de aprovisionamiento por defecto, como:
  • Realizar actualizaciones de tablas personalizadas
  • Auditoría personalizada
  • Enviar notificaciones personalizadas
Esto significa que tiene dos opciones para el procesamiento de aprovisionamiento mediante la integración de tablas de aplicación de base de datos:
  1. Utilizar la lógica por defecto proporcionada con el conector de tablas de aplicación de base de datos
  2. Utilizar la lógica personalizada implantada en los scripts
Los scripts personalizados solo se utilizan cuando se configuran en el sistema orquestado. Por lo tanto, si ha especificado un script de creación al crear el sistema orquestado, pero no hay ningún script para la actualización, el script personalizado se utilizará para la tarea de creación de aprovisionamiento, mientras que la tarea de actualización se implementará mediante el procesamiento del conector por defecto.

También debe tener en cuenta que todos los tipos de scripts personalizados son compatibles con un sistema orquestado configurado para el modo de sistema gestionado. El único tipo de secuencia de comandos admitido para el modo de origen autorizado es el tipo de carga de datos, que se admite para ambos modos.

Esquema de base de datos de ejemplo

Los ejemplos proporcionados en las siguientes secciones se basan en las tablas de base de datos que se describen en esta sección.

MYDBAT_PERSON

USE {dataBase};
CREATE TABLE MYDBAT_PERSON
  (USERID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
   USERNAME VARCHAR(50) NOT NULL,
   FIRSTNAME VARCHAR(50),
   LASTNAME VARCHAR(50),
   EMAIL VARCHAR(50) NOT NULL,
   COUNTRYCODE VARCHAR(20),
   DESCRIPTION VARCHAR(MAX),
   SALARY MONEY,
   JOININGDATE DATE,
   STATUS VARCHAR(20) NOT NULL,
   PASSWORD VARCHAR(MAX));

MYDBAT_GROUPS

USE {dataBase};
   CREATE TABLE MYDBAT_GROUPS
   (GROUPID VARCHAR(50) NOT NULL PRIMARY KEY,
   GROUPNAME VARCHAR(50) NOT NULL);

MYDBAT_ROLES

USE {dataBase};
   CREATE TABLE MYDBAT_ROLES
   (ROLEID varchar(50) NOT NULL PRIMARY KEY,
   ROLENAME varchar(50) NOT NULL);

MYDBAT_PERSON_GROUP

USE {dataBase};
   CREATE TABLE MYDBAT_PERSON_GROUP
   (USERID INT NOT NULL,
   GROUPID VARCHAR(50) NOT NULL,
   CONSTRAINT MYDBAT_PERSON_GROUP_PK PRIMARY KEY (USERID, GROUPID),
   CONSTRAINT MYDBAT_PERSON_FK1 FOREIGN KEY (USERID)
     REFERENCES MYDBAT_PERSON (USERID),
   CONSTRAINT MYDBAT_GROUPS_FK1 FOREIGN KEY (GROUPID)
     REFERENCES MYDBAT_GROUPS (GROUPID));

MYDBAT_PERSON_ROLE

USE {dataBase};
   CREATE TABLE MYDBAT_PERSON_ROLE  
   (USERID INT NOT NULL,
   ROLEID VARCHAR(50) NOT NULL,
   FROMDATE DATE,
   TODATE DATE,
   CONSTRAINT MYDBAT_PERSON_ROLE_PK PRIMARY KEY (USERID, ROLEID),
   CONSTRAINT MYDBAT_PERSON_FK2 FOREIGN KEY (USERID)
     REFERENCES MYDBAT_PERSON (USERID),
   CONSTRAINT MYDBAT_ROLES_FK1 FOREIGN KEY (ROLEID)
     REFERENCES MYDBAT_ROLES (ROLEID));

MYDBAT_COUNTRY

USE {dataBase};
   CREATE TABLE MYDBAT_COUNTRY
   (COUNTRYCODE VARCHAR(20) NOT NULL PRIMARY KEY,
   COUNTRYNAME VARCHAR(200) NOT NULL);
Nota

Las tablas secundarias, como mydbat_roles, mydbat_groups y mydbat_country, deben tener definida una restricción de clave primaria. Si no se define ninguna clave primaria para las tablas secundarias, la operación de validación fallará y verá el error Key for table <tablename> are not defined.

Argumentos de script Groovy

Los siguientes argumentos se pueden utilizar en los scripts de Groovy:

Argumentos de Script
Argumento Descripción
conector Objeto de conector de tablas de aplicación de base de datos.
tiempo

Cuando se llama al guión de Groovy. El atributo de tiempo también explica el tipo de operación que se está realizando. Por ejemplo, si se trata de una operación de búsqueda, también se devuelve la clase de objeto que se está buscando.

A continuación se muestra el formato del argumento de tiempo para la sincronización de campos de consulta:
executeQuery:OBJECT_CLASS
En este formato, OBJECT_CLASS se sustituye por el tipo de objeto que se está conciliando.
Por ejemplo, para un trabajo programado de sincronización de campo de consulta que contiene el tipo de objeto Rol, el valor del argumento de tiempo será el siguiente:
executeQuery:Role
atributos Todos los atributos.
rastreo Registrador como puente de rastreo de script a la aplicación
donde Cadena en la que la condición para ejecutar la consulta o es nula.
manejador resultSetHandler o SyncResultsHandler para los objetos de conector producidos por la consulta de ejecución, la operación de sincronización o la devolución nula.
ofertas Tipo de oferta de nombre de tabla que se va a utilizar en SQL. El valor por defecto es una cadena vacía. El valor de este argumento se obtiene de la configuración de integración.
nativeTimestamps Especifica si el script recupera los datos de registro de hora de las columnas como tipo java.sql.Timestamp de la tabla de base de datos. Esta información se obtiene de la configuración de integración.
allNative Especifica si el script debe recuperar el tipo de dato de las columnas en un formato nativo de la tabla de base de datos. El valor de este argumento se obtiene de la configuración de integración. El valor de este argumento especifica si el script debe devolver excepciones cuando se encuentra un código de error cero (0x00).
enableEmptyString Especifica si se debe activar la compatibilidad para escribir una cadena vacía en lugar de un valor NULL. El valor de este argumento se obtiene de la configuración de integración.
filterString Condición de filtro de cadena para la consulta de ejecución o nula.
filterParams Lista de parámetros de filtro. Cada parámetro está presente en el formato COLUMN_NAME:VALUE. Por ejemplo, FIRSTNAME:test.
sincronizar Nombre de la columna de base de datos configurada para la conciliación incremental. Este argumento está disponible en el script de sincronización, que se llama durante una ejecución de conciliación incremental.
sincronizado Valor del atributo de sincronización. Este argumento está disponible en el script de sincronización.

Ejemplo de script de carga de datos

El script de carga de datos lee los datos de todas las tablas de todas las entidades definidas. En este escenario, la carga de datos de término hace referencia a la carga de datos completa y a la carga de datos de consulta.

Este script de ejemplo lee los datos de usuario de la tabla MYDBAT_PERSON y los datos de relación de los usuarios de las tablas MYDABAT_PERSON_ROLE y MYDBAT_PERSON_GROUP. Los datos de derechos se leen en la tabla MYDBAT_GROUPS y los datos de consulta se leen en la tabla MYDBAT_COUNTRY. También soporta una búsqueda de filtros básica en la tabla MYDBAT_PERSON. Todas estas lecturas de datos se realizan mediante procedimientos almacenados.

Script de carga de datos

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.math.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.identityconnectors.framework.common.objects.*;
import java.lang.reflect.*;
import org.identityconnectors.common.security.GuardedString;
import java.text.*;
 
String ocName ;
var df = new SimpleDateFormat("yyyy-MM-dd");
var targetFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z");
if( timing != "") {
    trace.info("[Execute Query] timing attribute value: "+ timing);
    ocName = timing.split(":")[1]
}
     
trace.info("[Execute Query] for objectClass: "+ ocName);
switch (ocName) {
    //Lookup
    case "MYDBAT_COUNTRY":
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        try {
            callableStatement = conn.prepareCall("{call GET_COUNTRIES}");
            resultSet = (ResultSet) callableStatement.executeQuery();
             
            while (resultSet.next()) {
                var cob = new ConnectorObjectBuilder();
                cob.setObjectClass(new ObjectClass("MYDBAT_COUNTRY"));
                cob.addAttribute(AttributeBuilder.build(Uid.NAME, resultSet.getString(1)));
                cob.addAttribute(AttributeBuilder.build(Name.NAME, resultSet.getString(2)));
                 
                if(!handler.handle(cob.build())) return;
            }
        } finally {
            if(resultSet != null)
                resultSet.close();
            if(callableStatement != null)
                callableStatement.close();
        }
        break;
     
    //Entitlement
    case "MYDBAT_GROUPS":
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        try {
            callableStatement = conn.prepareCall("{call GET_GROUPS}");
            resultSet = (ResultSet) callableStatement.executeQuery();
             
            while (resultSet.next()) {
                var cob = new ConnectorObjectBuilder();
                cob.setObjectClass(new ObjectClass("MYDBAT_GROUPS"));
                cob.addAttribute(AttributeBuilder.build(Uid.NAME, resultSet.getString(1)));
                cob.addAttribute(AttributeBuilder.build(Name.NAME, resultSet.getString(2)));
                 
                if(!handler.handle(cob.build())) return;
            }
        } finally {
            if(resultSet != null)
                resultSet.close();
            if(callableStatement != null)
                callableStatement.close();
        }
        break;
     
    //Entitlement  
    case "DBAT_ROLES":
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;
        try {
            callableStatement = conn.prepareCall("{call GET_ROLES}");
            resultSet = (ResultSet) callableStatement.executeQuery();
             
            while (resultSet.next()) {
                var cob = new ConnectorObjectBuilder();
                cob.setObjectClass(new ObjectClass("MYDBAT_ROLES"));
                cob.addAttribute(AttributeBuilder.build(Uid.NAME, resultSet.getString(1)));
                cob.addAttribute(AttributeBuilder.build(Name.NAME, resultSet.getString(2)));
                 
                if(!handler.handle(cob.build())) return;
            }
        } finally {
            if(resultSet != null)
                resultSet.close();
            if(callableStatement != null)
                callableStatement.close();
        }
        break;
         
    case "ACCOUNT":
    case "TARGETACCOUNT":
        CallableStatement parentCallableStatement = null;
        ResultSet parentResultSet = null;
        try {
            if (filterString != "") {
                trace.info("[Execute Query] Performing Recon with Filter. Filter is:: "+ filterString +" And Filer Params are:: "+ filterParams);
                //[Execute Query] Performing Recon with Filter. Filter is::MYDBAT_PERSON.USERID = ? And Filer Params are::Params are:: [MYDBAT_PERSON.USERID:31]
                parentCallableStatement = conn.prepareCall("{call GET_PERSON_BY_USERID(?)}");
                parentCallableStatement.setString(1, filterParams.get(0).split(":")[1]);
            } else {
                trace.info("[Execute Query] Performing Full Recon.");
                parentCallableStatement = conn.prepareCall("{call GET_PERSONS}");
            }
            parentResultSet = (ResultSet) parentCallableStatement.executeQuery();
            while (parentResultSet.next()) {
                var cob = new ConnectorObjectBuilder();
                cob.setObjectClass(ObjectClass.ACCOUNT);
                cob.addAttribute(AttributeBuilder.build(Uid.NAME, parentResultSet.getString(1)));
                cob.addAttribute(AttributeBuilder.build("FIRSTNAME", parentResultSet.getString(2)));
                cob.addAttribute(AttributeBuilder.build("LASTNAME", parentResultSet.getString(3)));
                cob.addAttribute(AttributeBuilder.build("EMAIL", parentResultSet.getString(4)));
                cob.addAttribute(AttributeBuilder.build("DESCRIPTION", parentResultSet.getString(5)));
                cob.addAttribute(AttributeBuilder.build("SALARY", parentResultSet.getDouble(6)));
                var joiningDbDate = parentResultSet.getDate(7);
                if( joiningDbDate != null ) {
                    var date = df.parse(joiningDbDate.toString());
                    var joinDateStr = targetFormat.format(date);
                    var joinDate = date.getTime();
                    trace.info("date : "+ date +" ---- joinDate : "+ joinDate);
                    trace.info("Setting joinDate: "+ joinDate);
                    cob.addAttribute(AttributeBuilder.build("JOININGDATE", joinDate));
                }
                cob.addAttribute(AttributeBuilder.build(OperationalAttributes.ENABLE_NAME, "ACTIVE".equalsIgnoreCase(parentResultSet.getString(8))));
                cob.addAttribute(AttributeBuilder.build("COUNTRYCODE", parentResultSet.getString(9)));
                cob.addAttribute(AttributeBuilder.build(Name.NAME, parentResultSet.getString(10)));
     
                if (ocName.equals("TARGETACCOUNT")) {
                    CallableStatement callableStatement = null;
                    ResultSet resultSet = null;
                    try {
                        //Person role
                        callableStatement = conn.prepareCall("{call GET_PERSON_ROLE(?)}");
                        callableStatement.setString(1, parentResultSet.getString(1));
                        resultSet = (ResultSet) callableStatement.executeQuery();
                                 
                        var eoList = new ArrayList<EmbeddedObject>();
                         
                        while (resultSet.next()) {
                            var roleEA = new EmbeddedObjectBuilder();
                            roleEA.setObjectClass(new ObjectClass("MYDBAT_ROLES"));
                            roleEA.addAttribute(AttributeBuilder.build("ROLEID", resultSet.getString(2)));
                             
                            var fromDbDate = resultSet.getDate(3);
                            if( fromDbDate != null ) {
                                var date = df.parse(fromDbDate.toString());
                                var fromDateStr = targetFormat.format(date);
                                var fromDate = date.getTime();
                                trace.info("Setting roles fromDate : "+ fromDate);
                                roleEA.addAttribute(AttributeBuilder.build("FROMDATE", fromDate));
                            }
                             
                            var toDbDate = resultSet.getDate(4);
                            if( toDbDate != null ) {
                                var date = df.parse(toDbDate.toString());
                                var toDateStr = targetFormat.format(date);
                                var toDate = date.getTime();
                                trace.info("Setting roles toDate: "+ toDate);
                                roleEA.addAttribute(AttributeBuilder.build("TODATE", toDate));
                            }
                            eoList.add(roleEA.build());
                        }
                         
                        var roleEm = eoList.toArray(new EmbeddedObject[eoList.size()]);
                        cob.addAttribute(AttributeBuilder.build("MYDBAT_PERSON_ROLE", (Object[]) roleEm));
                    } finally {
                        if(resultSet != null)
                            resultSet.close();
                        if(callableStatement != null)
                            callableStatement.close();
                    }
                     
                    try {
                        //Person group
                        callableStatement = conn.prepareCall("{call GET_PERSON_GROUP(?)}");
                        callableStatement.setString(1, parentResultSet.getString(1));
                        resultSet = (ResultSet) callableStatement.executeQuery();
                         
                        var geoList = new ArrayList<EmbeddedObject>();
                         
                        while (resultSet.next()) {
                            var groupEA = new EmbeddedObjectBuilder();
                            groupEA.setObjectClass(new ObjectClass("MYDBAT_GROUPS"));
                            groupEA.addAttribute(AttributeBuilder.build("GROUPID", resultSet.getString(2)));
                            geoList.add(groupEA.build());
                        }
                         
                        var groupEm = geoList.toArray(new EmbeddedObject[geoList.size()]);
                        cob.addAttribute(AttributeBuilder.build("DBAT_PERSON_GROUP", (Object[]) groupEm));
                    } finally {
                        if( resultSet != null )
                            resultSet.close();
                        if( callableStatement != null )
                            callableStatement.close();
                    }
                }
                 
                if(!handler.handle(cob.build())) return;
            }
        } finally {
            if( parentResultSet != null )
                parentResultSet.close();
            if( parentCallableStatement != null )
                parentCallableStatement.close();
        }
        break;
}

Procedimiento Almacenado: Cargar Usuarios

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_PERSONS
AS
BEGIN
    SELECT USERID,
           FIRSTNAME,
           LASTNAME,
           EMAIL,
           DESCRIPTION,
           SALARY,
           JOININGDATE,
           STATUS,
           COUNTRYCODE,
           USERNAME
    FROM MYDBAT_PERSON
END;

Procedimiento almacenado: búsqueda de usuarios filtrados

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_PERSON_BY_USERID
@user_id INT
AS
BEGIN
   SELECT USERID,
          FIRSTNAME,
          LASTNAME,
          EMAIL,
          DESCRIPTION,
          SALARY,
          JOININGDATE,
          STATUS,
          COUNTRYCODE,
          USERNAME
   FROM MYDBAT_PERSON 
   WHERE USERID = @user_id;
END;
Este es un ejemplo muy básico de búsqueda de filtros con una sola condición de filtro, por ejemplo, MYDBAT_PERSON.USERID:21. Se utiliza específicamente para el procesamiento de writeBack después de la operación de creación

Procedimiento Almacenado: Obtener Roles

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_ROLES
AS
BEGIN
   SELECT ROLEID,
          ROLENAME 
   FROM MYDBAT_ROLES;
END;

Procedimiento Almacenado: Obtener Roles de Usuario

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_PERSON_ROLE
@user_id INT
AS
BEGIN
   SELECT USERID,
          ROLEID,
          FROMDATE,
          TODATE
   FROM MYDBAT_PERSON_ROLE WHERE USERID = @user_id
 END;

Procedimiento Almacenado: Obtener Grupos

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_GROUPS
AS
BEGIN
   SELECT GROUPID,
          GROUPNAME
   FROM MYDBAT_GROUPS;
 END;

Procedimiento Almacenado: Obtener Grupos de Usuarios

USE {dataBase};
 
CREATE OR ALTER PROCEDURE GET_PERSON_GROUP
@user_id INT
AS
BEGIN
   SELECT USERID,
          GROUPID
   FROM MYDBAT_PERSON_GROUP where USERID = @user_id;
END;

Procedimiento Almacenado: Obtener Consultas (País)

use {dataBase};
 
CREATE OR ALTER PROCEDURE GET_COUNTRIES
AS
BEGIN
   SELECT COUNTRYCODE,
          COUNTRYNAME
   FROM MYDBAT_COUNTRY;
 END;

Script de creación de muestra

Este script se llama durante el aprovisionamiento de una nueva cuenta desde Oracle Access Governance. Aquí estamos insertando datos en la tabla MYDBAT_PERSON.

Crear script

import java.sql.CallableStatement;
import java.sql.Types;
import java.util.Date.*;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.*;
import java.text.*;
       
CallableStatement callableStatement = null;
String uid = null;
try {
    trace.info("[Create-Groovy] Attributes:: " + attributes);
     
    callableStatement = conn.prepareCall("{call ADD_PERSON(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
    callableStatement.setString(1, attributes.get(Name.NAME) != null ? attributes.get(Name.NAME).getValue().get(0) : null);
    callableStatement.setString(2, attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null);
    callableStatement.setString(3, attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null);
    callableStatement.setString(4, attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null);
    callableStatement.setString(5, attributes.get("COUNTRYCODE") != null ? attributes.get("COUNTRYCODE").getValue().get(0) : null);
    callableStatement.setString(6, attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null);
    callableStatement.setString(7, (attributes.get(OperationalAttributes.ENABLE_NAME) != null ? attributes.get(OperationalAttributes.ENABLE_NAME).getValue().get(0) : true) ? "ACTIVE" : "INACTIVE");
     
    var joiningdate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null;
    callableStatement.setString(8, (joiningdate != null && joiningdate != 0) ? new SimpleDateFormat("yyyy-MM-dd").format(new Date(joiningdate)) : null); 
     
    var salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null;
    if(salary != null)
        callableStatement.setDouble(9, salary);
    else
        callableStatement.setNull(9, Types.DOUBLE)
     
    var password = attributes.get(OperationalAttributes.PASSWORD_NAME) != null ? attributes.get(OperationalAttributes.PASSWORD_NAME).getValue().get(0) : null;
    if (password != null) {
        password.access(new GuardedString.Accessor() {
            public void access(char[] clearChars) { callableStatement.setString(10, new String(clearChars));}
        });
    } else
        callableStatement.setString(10, null);
     
    callableStatement.registerOutParameter(11, Types.NVARCHAR);
    callableStatement.execute();
     
    uid = callableStatement.getString(11);
} finally {
    if (callableStatement != null)
        callableStatement.close();
}
trace.info("[Create] Created User:: " +uid);
return new Uid(uid);

Script secundario de adición de muestra

Este script se llama durante el aprovisionamiento de derechos/permisos a usuarios de Oracle Access Governance. Aquí estamos insertando datos en las tablas MYDBAT_PERSON_GROUP y MYDBAT_PERSON_ROLE.

Agregar script secundario

import java.sql.PreparedStatement;
import org.identityconnectors.framework.common.objects.*;
import java.text.*;
  
trace.info("[addMultiValuedAttributeScript-Groovy] Adding Child data:: " + attributes);
String userId = attributes.get(Uid.NAME).getValue().get(0);
PreparedStatement childst = null;
Attribute dbatChild = null;
try {
    dbatChild = attributes.get("MYDBAT_PERSON_GROUP");
    if (dbatChild != null) {
        var childDataEOSet = dbatChild.getValue();
        childst = conn.prepareStatement("INSERT INTO MYDBAT_PERSON_GROUP VALUES (?, ?)");
         
        if (childDataEOSet != null) {
            trace.info("[addMultiValuedAttributeScript] Adding Group data.");
            for ( iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next();
                attrsSet = eo.getAttributes();
                grpAttr = AttributeUtil.find("GROUPID", attrsSet);
                if (grpAttr != null) {
                    childst.setString(1, userId);
                    childst.setString(2, grpAttr.getValue().get(0));
                    childst.executeUpdate();
                    childst.clearParameters();
                }
            };
        }
    }
} finally {
    if (childst != null)
        childst.close();       
};
  
try {
    dbatChild = attributes.get("MYDBAT_PERSON_ROLE");
    if (dbatChild != null) {
        var childDataEOSet = dbatChild.getValue();
        childst = conn.prepareStatement("INSERT INTO MYDBAT_PERSON_ROLE VALUES (?, ?, ?, ?)");
         
        if (childDataEOSet != null) {
            trace.info("[addMultiValuedAttributeScript] Adding Role data.");
            for ( iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next();
                attrsSet = eo.getAttributes();
                roleattr = AttributeUtil.find("ROLEID", attrsSet);
                 
                if (roleattr != null) {
                    childst.setString(1, userId);
                    childst.setString(2, roleattr.getValue().get(0));
                    childst.setString(3, AttributeUtil.find("FROMDATE", attrsSet) != null ? new SimpleDateFormat("yyyy-MM-dd").format(new Date(AttributeUtil.find("FROMDATE", attrsSet).getValue().get(0))) : null);
                    childst.setString(4, AttributeUtil.find("TODATE", attrsSet) != null ? new SimpleDateFormat("yyyy-MM-dd").format(new Date(AttributeUtil.find("TODATE", attrsSet).getValue().get(0))) : null);   
                     
                    childst.executeUpdate();
                    childst.clearParameters();
                }
            };
        }
    }
} finally {
    if (childst != null)
        childst.close();
};

Script secundario de eliminación de muestra

Este script se llama al anular el aprovisionamiento de derechos/permisos de los usuarios de Oracle Access Governance. Aquí eliminamos datos de las tablas MYDBAT_PERSON_GROUP y MYDBAT_PERSON_ROLE mediante procedimientos almacenados.

Eliminar script secundario

import java.sql.CallableStatement;
import org.identityconnectors.framework.common.objects.*;
 
trace.info("[removeMultiValuedAttributeScript] Removing Child data:: "+ attributes);   
  
var uid = attributes.get(Uid.NAME).getValue().get(0);
CallableStatement callableStatement = null;
Attribute dbatChild = null;
try {
    dbatChild = attributes.get("MYDBAT_PERSON_GROUP");
    if (dbatChild != null) {
        var childDataEOSet = dbatChild.getValue();
        //Delete child data using stored procedure
        callableStatement = conn.prepareCall("{call DELETE_PERSON_GROUP(?, ?)}");
        if(childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Group data.");
            //Iterate through child data and delete
            for( iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next();
                grpattr = AttributeUtil.find("GROUPID", eo.getAttributes());
                if (grpattr != null) {
                    callableStatement.setString(1, uid);
                    callableStatement.setString(2, grpattr.getValue().get(0));
                    callableStatement.executeUpdate();
                    trace.info("[removeMultiValuedAttributeScript] Deleted Group:: "+ grpattr);
                }
            };
        }
    }
} finally {
    if (callableStatement != null)
        callableStatement.close();
};
 
try {
    dbatChild = attributes.get("MYDBAT_PERSON_ROLE");
    if (dbatChild != null) {
        var childDataEOSet = dbatChild.getValue();
        callableStatement = conn.prepareCall("{call DELETE_PERSON_ROLE(?, ?)}");
        if(childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Role data.");
            for ( iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next();
                roleattr = AttributeUtil.find("ROLEID", eo.getAttributes());
                if(roleattr != null) {
                    callableStatement.setString(1, uid);
                    callableStatement.setString(2, roleattr.getValue().get(0));
                    callableStatement.executeUpdate();
                    trace.info("[removeMultiValuedAttributeScript] Deleted Role:: "+ roleattr);
                }
            };
        }
    }
} finally {
    if (callableStatement != null)
        callableStatement.close();
};

Procedimiento almacenado: Eliminar secundario

USE {dataBase};
 
CREATE OR ALTER PROCEDURE DELETE_PERSON_GROUP
 @user_id INT, @group_id nvarchar(50)
 AS
 BEGIN
    DELETE from MYDBAT_PERSON_GROUP where USERID = @user_id AND GROUPID = @group_id
 END;

USE {dataBase};
 
CREATE OR ALTER PROCEDURE DELETE_PERSON_ROLE
 @user_id INT, @role_id nvarchar(50)
 AS
 BEGIN
   DELETE FROM MYDBAT_PERSON_ROLE where USERID = @user_id AND ROLEID = @role_id
 END;

Ejemplo de script de supresión

Este script se llama durante la revocación de una cuenta de Oracle Access Governance. Aquí se suprimen las tablas de relación de usuario de datos, MYDBAT_PERSON_ROLE y MYDBAT_PERSON_GROUP, así como los datos de la tabla MYDBAT_PERSON

Suprimir script

import java.sql.CallableStatement;
import org.identityconnectors.framework.common.objects.*;
    
var uid = attributes.get(Uid.NAME).getValue().get(0);
CallableStatement callableStatement = null;  
try {
    trace.info("[Delete-Groovy] Deleting user:: " + uid);
 
    callableStatement = conn.prepareCall("{call DELETE_PERSON(?)}");
    callableStatement.setString(1, uid);
    callableStatement.execute();
} finally {
    if (callableStatement != null)
        callableStatement.close();
};
trace.info("Deleted user:: " + uid);

Procedimiento Almacenado: Suprimir

USE {dataBase};
 
CREATE OR ALTER PROCEDURE DELETE_PERSON
 @user_id INT
 AS
 BEGIN
   DELETE FROM MYDBAT_PERSON_ROLE where USERID = @user_id;
   DELETE FROM MYDBAT_PERSON_GROUP where USERID = @user_id;
   DELETE FROM MYDBAT_PERSON WHERE USERID = @user_id;
 END;

Script de actualización de muestra

Este script se llama durante las operaciones de aprovisionamiento cuando la cuenta se actualiza desde Oracle Access Governance. Aquí estamos actualizando los datos de la tabla MYDBAT_PERSON

Actualizar script

import java.sql.PreparedStatement;
import java.sql.Types;
import org.identityconnectors.framework.common.objects.*;
import java.text.*;
import org.identityconnectors.framework.common.exceptions.*;
import org.identityconnectors.common.security.GuardedString;
   
trace.info("[Update-Groovy] Atrributes:: " + attributes);
 
PreparedStatement stmt = null;
String userId = null;
try {
    userId = attributes.get(Uid.NAME) != null ? attributes.get(Uid.NAME).getValue().get(0) : null;
     
    if (userId == null)
        throw new ConnectorException("UID Cannot be Null");
 
    stmt = conn.prepareStatement("UPDATE MYDBAT_PERSON SET FIRSTNAME = COALESCE(?, FIRSTNAME), LASTNAME = COALESCE(?, LASTNAME), EMAIL = COALESCE(?, EMAIL), COUNTRYCODE = COALESCE(?, COUNTRYCODE), DESCRIPTION = COALESCE(?, DESCRIPTION), STATUS = COALESCE(?, STATUS), JOININGDATE = COALESCE(?, JOININGDATE), SALARY = COALESCE(?, SALARY), PASSWORD = COALESCE(?, PASSWORD) WHERE USERID = ?");
    stmt.setString(1, attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null);
    stmt.setString(2, attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null);
    stmt.setString(3, attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null);
    stmt.setString(4, attributes.get("COUNTRYCODE") != null ? attributes.get("COUNTRYCODE").getValue().get(0) : null);
    stmt.setString(5, attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null);
    stmt.setString(6, (attributes.get(OperationalAttributes.ENABLE_NAME) != null ? attributes.get(OperationalAttributes.ENABLE_NAME).getValue().get(0) : true) ? "ACTIVE" : "INACTIVE");
     
    var joiningdate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null;
    stmt.setString(7, joiningdate != null ? new SimpleDateFormat("yyyy-MM-dd").format(new Date(joiningdate)) : null)
     
    var salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null;
    if(salary != null)
        stmt.setDouble(8, salary);
    else
        stmt.setNull(8, Types.DOUBLE)  
     
    var password = attributes.get(OperationalAttributes.PASSWORD_NAME) != null ? attributes.get(OperationalAttributes.PASSWORD_NAME).getValue().get(0) : null;
    if (password != null) {
        password.access(new GuardedString.Accessor() {
            public void access(char[] clearChars) { stmt.setString(9, new String(clearChars));}
        });
    } else
        stmt.setString(9, null);
    stmt.setString(10, userId);
     
    stmt.executeUpdate();
} finally {
    if (stmt != null)
        stmt.close();
};
trace.info("[Update] Updated user:: " + userId);
return new Uid(userId);