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

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

データベース・アプリケーション表の統合を使用して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 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);
ノート

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.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;
}

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

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;

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

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;
これは、MYDBAT_PERSON.USERID:21のように、フィルタ条件が1つのみのフィルタ検索の非常に基本的な例です。これは、作成操作後のwriteBack処理に特に使用されます。

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

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

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

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;

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

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

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

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;

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

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

サンプル作成スクリプト

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

スクリプトの作成

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);

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

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

子スクリプトの追加

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();
};

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

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

子スクリプトの削除

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();
};

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

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;

サンプル削除スクリプト

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

スクリプトの削除

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);

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

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;

サンプル更新スクリプト

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

スクリプトの更新

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);