Groovyを使用したデータベース・アプリケーション表のカスタム・スクリプトの開発(MySQL)

データベース・アプリケーション表(MySQL)のカスタム・スクリプトの概要

データベース・アプリケーション表の統合を使用してOracle Access Governanceからアカウントをプロビジョニングすると、作成、更新、削除などの操作が、指定されたデフォルト・コードを使用して実装されます。デフォルトで提供される操作を変更する場合は、オプションで、独自の特定のプロビジョニング操作要件を実装する独自のカスタム・スクリプトを指定できます。このステップは完全にオプションであり、デフォルトの操作で必要なものが提供される場合は、カスタム・スクリプトを作成する必要はありません。サポートされている任意の操作にカスタム・スクリプトを追加できます。カスタム・スクリプトを選択した場合は、デフォルトの操作を変更する必要がある場合にのみ追加する必要があります。ただし、サポートされている操作にはカスタム・スクリプトとデフォルト・スクリプトを組み合せて使用できますが、特定の操作ごとに1つのオプションのみを指定できます。たとえば、create操作は、組織に固有の機能を追加するカスタムスクリプトで実装できますが、delete操作は変更されず、デフォルトの機能が使用されます。

カスタム・スクリプトを使用するようにデータベース・アプリケーション表を実装および構成すると、次にプロビジョニング操作またはデータ・ロード操作を実行するときにそのスクリプトが使用されます。
ノート

カスタム・スクリプトは、Groovy形式を使用して実装する必要があります。その他のスクリプト形式はサポートされていません。
データベース・アプリケーション表のオーケストレート済システムを作成するときに、アカウント・データを含むデータベース・アプリケーションでの多数のプロビジョニング操作に対して実行するスクリプトを識別できます。操作は次のとおりです。
  • 作成
  • 更新
  • 削除
  • データロード
  • 関係データの追加
  • リレーションシップ・データの削除
これらのスクリプトは、エージェントのインストール・ディレクトリ(/app/<custom script> など)のエージェント・ホストに配置する必要があります。オーケストレート済システムの統合設定で、スクリプトの場所を使用してエージェントを構成します。エージェントを実行しているオペレーティング・システム・ユーザーに、カスタム・スクリプトに対する読取り/書込み権限があることを確認する必要があります。
プロビジョニング・タスクを実行すると、そのタスクに関連付けられた標準処理の代替としてスクリプトが実行されます。スクリプトは、作成や更新などのデフォルトのプロビジョニング・タスクを処理する必要があり、次のようなカスタム・タスクをデフォルト・プロビジョニング・プロセスの上位および超えて設定することもできます。
  • カスタム表更新の実行
  • カスタム監査
  • カスタム通知の送信
つまり、データベース・アプリケーション表の統合を使用して処理をプロビジョニングするには、次の2つのオプションがあります。
  1. Database Application Tablesコネクタに用意されているデフォルト・ロジックを使用します。
  2. スクリプトに実装されたカスタム・ロジックの使用
カスタム・スクリプトは、オーケストレート済システムで構成されている場合にのみ使用されます。そのため、オーケストレート済システムの作成時に作成スクリプトを指定したが、更新用のスクリプトを指定しなかった場合は、プロビジョニングの作成タスクにカスタム・スクリプトが使用され、更新タスクはデフォルトのコネクタ処理を使用して実装されます。

また、すべてのカスタム・スクリプト・タイプは、管理対象システム・モード用に構成されたオーケストレート済システムでサポートされていることにも注意してください。認可ソース・モードでサポートされているスクリプト・タイプは、両方のモードでサポートされているデータロード・タイプのみです。

サンプル・データベース・スキーマ

次の項で説明するサンプルは、この項で説明するデータベース表に基づいています。

MYDBAT_PERSON

USE {dataBase};
 
CREATE TABLE MYDBAT_PERSON (
    USERID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    USERNAME VARCHAR(50) NOT NULL,
    FIRSTNAME VARCHAR(50),
    LASTNAME VARCHAR(50),
    EMAIL VARCHAR(50) NOT NULL,
    COUNTRYCODE VARCHAR(20),
    DESCRIPTION VARCHAR(50),
    SALARY DECIMAL(10, 2),
    JOININGDATE DATE,
    STATUS VARCHAR(50),
    LASTUPDATED TIMESTAMP(6),
    PASSWORD VARCHAR(50));

MYDBAT_GROUPS

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

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(20) NOT NULL,
    PRIMARY KEY (USERID,GROUPID));

ALTER TABLE DBAT_PERSON_GROUP
ADD CONSTRAINT FK_USERID
FOREIGN KEY (USERID) REFERENCES DBAT_PERSON(USERID);

MYDBAT_PERSON_ROLE

USE {dataBase};
 
CREATE TABLE MYDBAT_PERSON_ROLE(
    USERID INT NOT NULL,
    ROLEID VARCHAR(20) NOT NULL,
    PRIMARY KEY (USERID,ROLEID));

ALTER TABLE MYDBAT_PERSON_ROLE
ADD CONSTRAINT FK_USERIDROLE
FOREIGN KEY (USERID) REFERENCES DBAT_PERSON(USERID);

MYDBAT_COUNTRY

USE {dataBase};
 
CREATE TABLE MYDBAT_COUNTRY(
    COUNTRYCODE VARCHAR(20) NOT NULL,
    COUNTRYNAME VARCHAR(20) NOT NULL,
    PRIMARY KEY (COUNTRYCODE)
);
ノート

mydbat_rolesmydbat_groupsmydbat_countryなどの子表には、主キー制約が定義されている必要があります。子表に主キーが定義されていない場合、検証操作は失敗し、「表<tablename>のキーが定義されていません」というエラーが表示されます。

Groovyスクリプト引数

Groovyスクリプトでは、次の引数を使用できます:

スクリプト引数
引数 説明
コネクター Database Application Tablesコネクタ・オブジェクト。
タイミング

Groovyスクリプトが呼び出されるタイミング。また、timing属性は、実行される操作のタイプも説明します。たとえば、検索操作の場合、検索対象のオブジェクト・クラスも返されます。

次に、参照フィールド同期のtiming引数の書式を示します。
executeQuery:OBJECT_CLASS
この書式で、OBJECT_CLASSは、リコンサイルされるオブジェクトのタイプに置き換えられます。
たとえば、オブジェクト・タイプRoleを含む参照フィールド同期のスケジュール済ジョブの場合は、timing引数の値は次のようになります。
executeQuery:Role
属性 すべての属性
トレース アプリケーションへのスクリプト・トレース・ブリッジとしてのロガー。
内容 問合せの実行の条件の文字列、またはnull。
ハンドラ 問合せの実行、同期操作、またはNULLの返却により生成されるコネクタ・オブジェクトのresultSetHandlerまたはSyncResultsHandler。
引用 SQLで使用される表名の引用符のタイプ。デフォルト値が空の文字列です。この引数の値は、統合設定から取得されます。
nativeTimestamps スクリプトによって、データベース表からjava.sql.Timestampタイプとして列のタイムスタンプ・データを取得するかどうかを指定します。この情報は、統合設定から取得されます。
allNative スクリプトによって、データベース表からネイティブ形式で列のデータ型を取得するかどうかを指定します。この引数の値は、統合設定から取得されます。この引数の値によって、ゼロ(0x00)のエラー・コードが出現したときに、スクリプトで例外をスローするかどうかを指定します。
enableEmptyString NULL値のかわりに空の文字列の書込みのサポートを有効化するかどうかを指定します。この引数の値は、統合設定から取得されます。
filterString 問合せの実行の文字列フィルタ条件、またはnull。
filterParams フィルタ・パラメータのリスト。各パラメータは、COLUMN_NAME:VALUEの形式で存在します。たとえば、FIRSTNAME:testです。
同期属性 増分リコンシリエーション用に構成されたデータベース列の名前。この引数は、増分リコンシリエーションの実行中に呼び出される同期スクリプトで使用できます。
シンクトークン 同期属性の値。この引数は、同期スクリプトで使用できます。

サンプルデータロードスクリプト

データ・ロード・スクリプトは、すべての定義済エンティティのすべての表からデータを読み取ります。このシナリオでは、データ・ロードという用語は、完全なデータ・ロードと参照データ・ロードを指します。

このサンプル・スクリプトは、MYDBAT_PERSON表からユーザー・データを読み取り、MYDABAT_PERSON_ROLE表およびMYDBAT_PERSON_GROUP表からユーザーの関係データを読み取ります。権限データはMYDBAT_GROUPS表から読み取られ、参照データはMYDBAT_COUNTRY表から読み取られます。また、MYDBAT_PERSON表での基本的なフィルタ検索もサポートされています。これらのすべてのデータ読取りは、ストアド・プロシージャを使用して行われます。

データロード・スクリプト

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.identityconnectors.framework.common.objects.*;
import org.identityconnectors.common.security.GuardedString;
 
ResultSet rs = null;
CallableStatement st = null;
 
try {
    String ocName = "";
    if (timing != "") {
        trace.info("[Execute Query] timing attribute value: " + timing);
        ocName = timing.split(":")[1];
    }
 
    trace.info("[Execute Query] for objectClass: " + ocName);
 
    if (ocName.equals("ACCOUNT") || ocName.equals("TARGETACCOUNT")) {
        if (filterString != "") {
            trace.info("[Execute Query] Performing Recon with Filter. Filter is: " + filterString + " And Filter Params are: " + filterParams);
            // Example: Filter is MYDBAT_PERSON.USERID = ? And Filter Params are [MYDBAT_PERSON.USERID:21]
            String[] filter = filterParams.get(0).split(":");
            st = conn.prepareCall("{call EXECUTE_QUERY_WITH_FILTER(?, ?)}");
            st.setString(1, filter[0]); // Column name (e.g., MYDBAT_PERSON.USERID)
            st.setInt(2, Integer.parseInt(filter[1])); // Value to filter (e.g., 21)
        } else {
            trace.info("[Execute Query] Performing Full Recon.");
            st = conn.prepareCall("{call EXECUTE_QUERY_PERSON()}");
        }
 
        // Execute the procedure and get the ResultSet
        rs = st.executeQuery(); // No need to register OUT parameter
        SimpleDateFormat targetFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(ObjectClass.ACCOUNT);
 
            Attribute fname = AttributeBuilder.build("FIRSTNAME", rs.getString("FIRSTNAME"));
            Attribute lname = AttributeBuilder.build("LASTNAME", rs.getString("LASTNAME"));
            Attribute uid = AttributeBuilder.build("__UID__", rs.getString("USERID"));
            Attribute name = AttributeBuilder.build("__NAME__", rs.getString("USERNAME"));
            Attribute email = AttributeBuilder.build("EMAIL", rs.getString("EMAIL"));
            Attribute description = AttributeBuilder.build("DESCRIPTION", rs.getString("DESCRIPTION"));
 
            Date dbDate = rs.getDate("JOININGDATE");
            String joinDateStr = null;
            Long joinDate = null;
            if (dbDate != null) {
                java.util.Date date = df.parse(dbDate.toString());
                joinDateStr = targetFormat.format(date);
                joinDate = date.getTime();
                trace.info("date: " + date + " ---- joinDate: " + joinDate);
            }
 
            if (joinDate != null) {
                trace.info("Setting joinDate: " + joinDate);
                Attribute joindate = AttributeBuilder.build("JOININGDATE", joinDate);
                cob.addAttribute(joindate);
            }
 
            Attribute status = AttributeBuilder.build("STATUS", rs.getString("STATUS"));
            Attribute countryCode = AttributeBuilder.build("COUNTRYCODE", rs.getString("COUNTRYCODE"));
 
            cob.addAttribute(fname);
            cob.addAttribute(lname);
            cob.addAttribute(uid);
            cob.addAttribute(name);
            cob.addAttribute(email);
            cob.addAttribute(description);
            cob.addAttribute(status);
            cob.addAttribute(countryCode);
 
            if (!handler.handle(cob.build())) return;
        }
    } else if (ocName.equals("DBAT_COUNTRY")) {
        trace.info("[Execute Query] for Lookup: " + ocName);
        CallableStatement countryStmt = conn.prepareCall("{call GET_COUNTRIES()}");
        rs = countryStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_COUNTRY"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        countryStmt.close();
    } else if (ocName.equals("DBAT_GROUPS")) {
        trace.info("[Execute Query] for Entitlement: " + ocName);
        CallableStatement groupStmt = conn.prepareCall("{call GET_GROUPS()}");
        rs = groupStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_GROUPS"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        groupStmt.close();
    }else if (ocName.equals("DBAT_ROLES")) {
        trace.info("[Execute Query] for Entitlement: " + ocName);
        CallableStatement groupStmt = conn.prepareCall("{call GET_ROLES()}");
        rs = groupStmt.executeQuery();
 
        while (rs.next()) {
            ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
            cob.setObjectClass(new ObjectClass("DBAT_ROLESS"));
            Attribute groupId = AttributeBuilder.build("__UID__", rs.getString(1));
            Attribute groupName = AttributeBuilder.build("__NAME__", rs.getString(2));
            cob.addAttribute(groupId);
            cob.addAttribute(groupName);
            if (!handler.handle(cob.build())) return;
        }
 
        rs.close();
        groupStmt.close();
    }
} finally {
    if (rs != null) rs.close();
    if (st != null) st.close();
}

ストアド・プロシージャ: ユーザーのロード

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE EXECUTE_QUERY_PERSON()
BEGIN
  SELECT USERID,
         FIRSTNAME,
         LASTNAME,
         EMAIL,
         DESCRIPTION,
         SALARY,
         JOININGDATE,
         STATUS,
         COUNTRYCODE,
         USERNAME
  FROM MYDBAT_PERSON;
END //
DELIMITER ;

ストアド・プロシージャ: フィルタ済ユーザー検索

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE EXECUTE_QUERY_WITH_FILTER(
  IN filter VARCHAR(255),
  IN filterValue int
)
BEGIN
  SET @sql_query = CONCAT(
    'SELECT USERID,
            FIRSTNAME,
            LASTNAME,
            EMAIL,
            DESCRIPTION,
            SALARY,
            JOININGDATE,
            STATUS,
            COUNTRYCODE,
            USERNAME ',
    'FROM MYDBAT_PERSON WHERE ', filter, ' = ?'
  );
 
  PREPARE stmt FROM @sql_query;
  SET @filter_value = filterValue;
   
  EXECUTE stmt USING @filter_value;
   
  DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
これは、MYDBAT_PERSON.USERID:21のように、フィルタ条件が1つのみのフィルタ検索の非常に基本的な例です。これは、作成操作後のwriteBack処理に特に使用されます。

ストアド・プロシージャ: ロールの取得

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_ROLES()
BEGIN
  SELECT ROLEID,
         ROLENAME
  FROM MYDBAT_ROLES;
END //
DELIMITER ;

ストアド・プロシージャ: ユーザー・ロールの取得

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_USERROLE(
  IN userin int
)
BEGIN
  SELECT USERID,
         ROLEID,
         FROMDATE,
         TODATE
  FROM MYDBAT_PERSON_ROLE
  WHERE USERID = userin;
END //
DELIMITER ;

ストアド・プロシージャ: グループの取得

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_GROUPS()
BEGIN
  SELECT GROUPID,
         GROUPNAME
  FROM MYDBAT_GROUPS;
END //
DELIMITER ;

ストアド・プロシージャ: ユーザー・グループの取得

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_USERGROUP(
  IN userin int
)
BEGIN
  SELECT USERID,
         GROUPID
  FROM MYDBAT_PERSON_GROUP
  WHERE USERID = userin;
END //
DELIMITER ;

ストアド・プロシージャ: 参照の取得(国)

USE {dataBase};
 
DELIMITER //
CREATE PROCEDURE GET_COUNTRIES()
BEGIN
  SELECT COUNTRYCODE,
         COUNTRYNAME
  FROM MYDBAT_COUNTRY;
END //
DELIMITER ;

サンプル作成スクリプト

このスクリプトは、Oracle Access Governanceからの新規アカウントのプロビジョニング中に起動されます。ここでは、MYDBAT_PERSON表にデータを挿入します。

スクリプトの作成

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.CallableStatement;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.*;
 
trace.info("[Create-Groovy] Attributes::" + attributes);
 
// Get all the attributes from script argument
GuardedString pass = attributes.get("__PASSWORD__") != null ? attributes.get("__PASSWORD__").getValue().get(0) : null;
String uname = attributes.get("__NAME__") != null ? attributes.get("__NAME__").getValue().get(0) : null;
boolean enableValue = attributes.get("__ENABLE__") != null ? attributes.get("__ENABLE__").getValue().get(0) : true;
String email = attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null;
String first = attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null;
String last = attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null;
String desc = attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null;
Object salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null; // Changed to Object
String countryCode = attributes.get("COUNTRYCODE") != null ? attributes.get("COUNTRYCODE").getValue().get(0) : null;
Object joiningdate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null; // Changed to Object
 
// Prepare callable statement for the stored procedure
CallableStatement createStmt = null;
 
try {
    // Prepare the SQL statement to call the stored procedure
    createStmt = conn.prepareCall("{CALL ADD_PERSON(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
 
    // Set the input parameters for the stored procedure
    createStmt.setString(1, uname);    // USERNAME
    createStmt.setString(2, first);    // FIRSTNAME
    createStmt.setString(3, last);     // LASTNAME
    createStmt.setString(4, email);    // EMAIL
    createStmt.setString(5, countryCode); // COUNTRYCODE
    createStmt.setString(6, desc);     // DESCRIPTION
 
    // Handling SALARY: Ensure it's numeric or set as NULL
    if (salary != null && salary instanceof String) {
        try {
            createStmt.setBigDecimal(9, new BigDecimal((String) salary)); // Parse to BigDecimal
        } catch (NumberFormatException e) {
            trace.error("[Create-Groovy] Invalid SALARY format: " + salary);
            createStmt.setNull(9, java.sql.Types.DECIMAL); // Set NULL if invalid
        }
    } else {
        createStmt.setNull(9, java.sql.Types.DECIMAL); // NULL for SALARY if not provided
    }
 
    // Handling JOININGDATE: Convert from long to MySQL DATE format
    if (joiningdate != null) {
        if (joiningdate instanceof Long) {
            // Convert long to java.util.Date
            Date dateObj = new Date((Long) joiningdate);
            // Format the date to 'yyyy-MM-dd'
            SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
            String formattedDate = dateFormatter.format(dateObj);
            createStmt.setString(8, formattedDate); // Set the formatted date
        } else {
            trace.error("[Create-Groovy] Invalid JOININGDATE format: Expected Long but got " + joiningdate.getClass());
            createStmt.setNull(8, java.sql.Types.DATE); // Set NULL if the format is invalid
        }
    } else {
        createStmt.setNull(8, java.sql.Types.DATE); // NULL for JOININGDATE if not provided
    }
 
    // STATUS: ACTIVE or INACTIVE
    if (enableValue) {
        createStmt.setString(7, "ACTIVE"); // STATUS
    } else {
        createStmt.setString(7, "INACTIVE"); // STATUS
    }
 
    // PASSWORD Handling
    if (pass != null) {
        pass.access(new GuardedString.Accessor() {
            public void access(char[] clearChars) {
                createStmt.setString(10, new String(clearChars)); // PASSWORD
            }
        });
    } else {
        createStmt.setString(10, null); // NULL for PASSWORD if not provided
    }
 
    // The output parameter for USERID (generated by the stored procedure)
    createStmt.registerOutParameter(11, java.sql.Types.VARCHAR);
 
    // Execute the stored procedure
    createStmt.executeUpdate();
 
    // Retrieve the generated USERID (either auto-increment or UUID)
    String generatedUserId = createStmt.getString(11); // Get the output parameter (USERID)
    trace.info("[Create] Created User with USERID::" + generatedUserId);
 
    // Return the generated USERID as Uid
    return new Uid(generatedUserId);
 
} catch (Exception e) {
    trace.error("[Create-Groovy] Error during user creation: " + e.getMessage());
    throw e;  // Re-throw exception to signal failure
} finally {
    // Clean up resources
    if (createStmt != null) {
        createStmt.close();
    }
}

アカウント・ストアド・プロシージャの作成

DELIMITER $$
  
CREATE PROCEDURE ADD_PERSON (
    IN USERNAME VARCHAR(50),
    IN FIRSTNAME VARCHAR(50),
    IN LASTNAME VARCHAR(50),
    IN EMAIL VARCHAR(50),
    IN COUNTRYCODE VARCHAR(20),
    IN DESCRIPTION VARCHAR(50),
    IN STATUS VARCHAR(50),
    IN JOININGDATE DATE,
    IN SALARY DECIMAL(10,2),
    IN PASSWORD VARCHAR(50),
    OUT USERID VARCHAR(50)
)
BEGIN
    DECLARE generated_user_id VARCHAR(50);
    DECLARE is_auto_increment VARCHAR(50);  -- Change to VARCHAR to hold string values like 'auto_increment'
  
    -- Check if USERID column has the 'auto_increment' flag in the EXTRA column
    SELECT EXTRA
    INTO is_auto_increment
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'MYDBAT_PERSON'
      AND COLUMN_NAME = 'USERID'
      AND TABLE_SCHEMA = DATABASE();
  
    -- Check if 'auto_increment' is present in the EXTRA column
    IF is_auto_increment LIKE '%auto_increment%' THEN
        -- If USERID is auto-increment
        INSERT INTO MYDBAT_PERSON (
            USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        )
        VALUES (
            USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        );
        -- Retrieve the auto-generated USERID and cast it to VARCHAR
        SET USERID = CAST(LAST_INSERT_ID() AS CHAR);
    ELSE
        -- If USERID is NOT auto-increment, generate a UUID for USERID
        SET generated_user_id = UUID();
        -- Insert the record with the generated UUID
        INSERT INTO MYDBAT_PERSON (
            USERID, USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        )
        VALUES (
            generated_user_id, USERNAME, FIRSTNAME, LASTNAME, EMAIL, COUNTRYCODE, DESCRIPTION, STATUS, JOININGDATE, SALARY, PASSWORD
        );
        -- Set the generated UUID in the output, as a VARCHAR
        SET USERID = generated_user_id;
    END IF;
END$$
  
DELIMITER ;

このストアド・プロシージャは、データベースにユーザーを作成するためのサンプル実装です。このスクリプトは、MYDBAT_PERSON表のUSERID列に自動インクリメント・セットがあるかどうかをチェックします。これは、ユーザーIDが自動的に移入されることを意味します。自動インクリメントが設定されている場合は、ユーザーがユーザーIDなしでSQL文を使用して作成されます。これは、データベースによって自動的に設定されるためです。自動インクリメントが設定されていない場合、ユーザーIDを生成してMYDBAT_PERSON表に挿入するSQL文を使用してユーザーが作成されます。USERIDの実装は実装によって異なる場合があるため、このストアド・プロシージャは特定の要件に従う必要があります。

子スクリプトの追加のサンプル

このスクリプトは、Oracle Access Governanceからユーザーへの権限/権限のプロビジョニング中に起動されます。ここでは、MYDBAT_PERSON_GROUP表およびMYDBAT_PERSON_ROLE表にデータを挿入します。

子スクリプトの追加

import org.identityconnectors.framework.common.objects.*
import java.text.*
 
trace.info("[addMultiValuedAttributeScript-Groovy] Adding Child data::" + attributes)
childst = null
try {
    // Adding Group data
    childDataEOSet = null
     
    // Logic for handling simple multi-valued attributes
    if (attributes.get("MYDBAT_PERSON_GROUP") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_GROUP").getValue()
        childst = conn.prepareStatement("INSERT INTO dbat.MYDBAT_PERSON_GROUP (USERID, GROUPID) VALUES (?, ?)")
        int id = attributes.get("__UID__").getValue().get(0).toInteger()
         
        if (childDataEOSet != null) {
            trace.info("[addMultiValuedAttributeScript] Adding Group data.")
            // Iterate through child data and insert into table
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                grpattr = AttributeUtil.find("GROUPID", attrsSet)
                 
                if (grpattr != null) {
                    // Extract group ID and insert record
                    groupid = grpattr.getValue().get(0)
                    childst.setInt(1, id)
                    childst.setString(2, groupid)
                    childst.executeUpdate()
                    childst.clearParameters()
                }
            }
        }
    }
} finally {
    if (childst != null)
        childst.close()
}
 
try {
    childDataEOSet = null
    // Logic for handling complex multi-valued attributes
    if (attributes.get("MYDBAT_PERSON_ROLE") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_ROLE").getValue()
        childst = conn.prepareStatement("INSERT INTO dbat.MYDBAT_PERSON_ROLE (USERID, ROLEID) VALUES (?, ?)")
         
        int id = attributes.get("__UID__").getValue().get(0).toInteger()
         
        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) {
                    // Extract role ID and insert record
                    roleid = roleattr.getValue().get(0)
                    childst.setInt(1, id)
                    childst.setString(2, roleid)
                     
                    childst.executeUpdate()
                    childst.clearParameters()
                }
            }
        }
    }
} finally {
    if (childst != null)
        childst.close()
}

子スクリプトの削除のサンプル

このスクリプトは、Oracle Access Governanceからユーザーからの権限/権限のプロビジョニング解除時に起動されます。ここでは、ストアド・プロシージャを使用してMYDBAT_PERSON_GROUP表およびMYDBAT_PERSON_ROLE表からデータを削除します。

子スクリプトの削除

import org.identityconnectors.framework.common.objects.*
 
trace.info("[removeMultiValuedAttributeScript] Removing Child data::" + attributes)
 
try {
    childDataEOSet = null
    delSt = null
    // Get UID and convert to int
    int id = Integer.parseInt(attributes.get("__UID__").getValue().get(0))
     
    // Handle removal of person group data
    if (attributes.get("MYDBAT_PERSON_GROUP") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_GROUP").getValue()
         
        // Call the MySQL stored procedure
        delSt = conn.prepareCall("{CALL DELETE_USERGROUP(?, ?)}")
         
        if (childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Group data.")
            // Iterate through child data and delete
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                grpattr = AttributeUtil.find("GROUPID", attrsSet)
                 
                if (grpattr != null) {
                    groupid = grpattr.getValue().get(0)
                    delSt.setInt(1, id) // Use setInt for integer ID
                    delSt.setString(2, groupid)
                    delSt.executeUpdate()
                    trace.info("[removeMultiValuedAttributeScript] Deleted Group::" + groupid)
                }
            }
        }
    }
} finally {
    if (delSt != null)
        delSt.close()
}
 
try {
    childDataEOSet = null
    delSt = null
    // Get UID and convert to int
    int id = Integer.parseInt(attributes.get("__UID__").getValue().get(0))
     
    // Handle removal of person role data
    if (attributes.get("MYDBAT_PERSON_ROLE") != null) {
        childDataEOSet = attributes.get("MYDBAT_PERSON_ROLE").getValue()
         
        // Call the MySQL stored procedure
        delSt = conn.prepareCall("{CALL DELETE_USERROLE(?, ?)}")
         
        if (childDataEOSet != null) {
            trace.info("[removeMultiValuedAttributeScript] Removing Role data.")
            for (iterator = childDataEOSet.iterator(); iterator.hasNext(); ) {
                eo = iterator.next()
                attrsSet = eo.getAttributes()
                roleattr = AttributeUtil.find("ROLEID", attrsSet)
                 
                if (roleattr != null) {
                    rolename = roleattr.getValue().get(0)
                    delSt.setInt(1, id) // Use setInt for integer ID
                    delSt.setString(2, rolename)
                    delSt.executeUpdate()
                    trace.info("[removeMultiValuedAttributeScript] Deleted Role::" + rolename)
                }
            }
        }
    }
} finally {
    if (delSt != null)
        delSt.close()
}

ストアド・プロシージャ: 子の削除

ユーザー役割の削除
DELIMITER $$
  
CREATE PROCEDURE DELETE_USERROLE (
    IN input_userid INT,
    IN input_roleid VARCHAR(20)
)
BEGIN
    -- Check if the record exists before attempting deletion
    IF EXISTS (
        SELECT 1
        FROM MYDBAT_PERSON_ROLE
        WHERE USERID = input_userid AND ROLEID = input_roleid
    ) THEN
        -- Perform the deletion
        DELETE FROM MYDBAT_PERSON_ROLE
        WHERE USERID = input_userid AND ROLEID = input_roleid;
    ELSE
        -- If no record exists, signal an error or do nothing
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'The specified USERID and ROLEID combination does not exist in MYDBAT_PERSON_ROLE.';
    END IF;
END$$
  
DELIMITER ;
ユーザー・グループの削除
DELIMITER $$
  
CREATE PROCEDURE DELETE_USERGROUP (
    IN input_userid INT,
    IN input_groupid VARCHAR(20)
)
BEGIN
    -- Check if the record exists before attempting deletion
    IF EXISTS (
        SELECT 1
        FROM MYDBAT_PERSON_GROUP
        WHERE USERID = input_userid AND GROUPID = input_groupid
    ) THEN
        -- Perform the deletion
        DELETE FROM MYDBAT_PERSON_GROUP
        WHERE USERID = input_userid AND GROUPID = input_groupid;
    ELSE
        -- If no record exists, signal an error or do nothing
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'The specified USERID and GROUPID combination does not exist in MYDBAT_PERSON_GROUP.';
    END IF;
END$$
  
DELIMITER ;

サンプル削除スクリプト

このスクリプトは、Oracle Access Governanceからのアカウントの失効時に起動されます。ここでは、データ・ユーザー関係表MYDBAT_PERSON_ROLEおよびMYDBAT_PERSON_GROUPと、MYDBAT_PERSON表からのデータを削除します。

スクリプトの削除

import java.sql.PreparedStatement;
import org.identityconnectors.framework.common.objects.*;
 
// Get the UID from the input map 'attributes'
String uid = attributes.get("__UID__").getValue().get(0);
trace.info("[Delete-Groovy] Deleting user:: " + uid);
 
try {
    // Delete data from child tables and then, main table
    // Delete user roles
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON_ROLE WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
    st.close();
 
    // Delete user groups
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON_GROUP WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
    st.close();
 
    // Delete user account
    st = conn.prepareStatement("DELETE FROM dbat.MYDBAT_PERSON WHERE userid=?");
    st.setString(1, uid);
    st.executeUpdate();
} finally {
    if (st != null)
        st.close();
};
 
trace.info("Deleted user:: " + uid);

サンプル更新スクリプト

このスクリプトは、アカウントがOracle Access Governanceから更新されたときにプロビジョニング操作中に起動されます。ここでは、MYDBAT_PERSON表のデータを更新します。

スクリプトの更新

import org.identityconnectors.framework.common.objects.*;
import java.text.*;
import org.identityconnectors.framework.common.exceptions.*;
import java.sql.*;
 
trace.info("[Update-Groovy] Attributes::" + attributes);
 
/** During an Update operation, AGCS sends the UID attribute along with updated attributes. Get all the values of attributes **/
String id = attributes.get("__UID__") != null ? attributes.get("__UID__").getValue().get(0) : null;
String firstName = attributes.get("FIRSTNAME") != null ? attributes.get("FIRSTNAME").getValue().get(0) : null;
String lastName = attributes.get("LASTNAME") != null ? attributes.get("LASTNAME").getValue().get(0) : null;
String email = attributes.get("EMAIL") != null ? attributes.get("EMAIL").getValue().get(0) : null;
String description = attributes.get("DESCRIPTION") != null ? attributes.get("DESCRIPTION").getValue().get(0) : null;
String salary = attributes.get("SALARY") != null ? attributes.get("SALARY").getValue().get(0) : null;
String joindate = attributes.get("JOININGDATE") != null ? attributes.get("JOININGDATE").getValue().get(0) : null;
Boolean enableValue = attributes.get("__ENABLE__") != null ? attributes.get("__ENABLE__").getValue().get(0) : true;
 
// Throw exception if uid is null
if (id == null) throw new ConnectorException("UID Cannot be Null");
 
PreparedStatement stmt = null;
try {
    // Create prepared statement to update the MYDBAT_PERSON table
    stmt = conn.prepareStatement("UPDATE dbat.MYDBAT_PERSON SET FIRSTNAME=IFNULL(?, FIRSTNAME), LASTNAME=IFNULL(?, LASTNAME), EMAIL=IFNULL(?, EMAIL), SALARY=IFNULL(?, SALARY), JOININGDATE=IFNULL(?, JOININGDATE), STATUS=IFNULL(?, STATUS) WHERE USERID =?");
 
    // Set SQL input parameters
    stmt.setString(1, firstName); // First name
    stmt.setString(2, lastName); // Last name
    stmt.setString(3, email);    // Email
 
    // Handle salary: Convert to BigDecimal if not null, otherwise set SQL NULL
    if (salary != null) {
        stmt.setBigDecimal(4, new BigDecimal(salary));
    } else {
        stmt.setNull(4, java.sql.Types.DECIMAL); // Set SQL NULL for salary
    }
 
    // Handle joindate: Convert to MySQL date format if not null
    String dateStr = null;
    if (joindate != null) {
        Date date = new Date(joindate);
        DateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd"); // MySQL date format
        dateStr = targetFormat.format(date);
    }
    stmt.setString(5, dateStr); // Joining date
 
    // Handle enable/disable status
    if (enableValue) {
        stmt.setString(6, "Enabled");
    } else {
        stmt.setString(6, "Disabled");
    }
 
    // Set UID for the WHERE condition
    stmt.setString(7, id);
 
    // Execute the update
    stmt.executeUpdate();
} finally {
    // Ensure the statement is closed to release resources
    if (stmt != null) stmt.close();
}
 
trace.info("[Update] Updated user::" + id);
return new Uid(id);