6.1 トリプルレベル・セキュリティ

トリプルレベル・セキュリティ・オプションでは、ラベル・セキュリティのOracle AI Databaseネイティブ・サポートの上に、RDF固有の機能の薄いレイヤーが実現されます。

トリプルレベル・セキュリティを使用するには、SEM_RDFSA.APPLY_OLS_POLICYプロシージャの実行時に、rdfsa_optionsパラメータ値としてSEM_RDFSA.TRIPLE_LEVEL_ONLYを指定します。たとえば、次のようにします。

EXECUTE sem_rdfsa.apply_ols_policy('defense', SEM_RDFSA.TRIPLE_LEVEL_ONLY, network_owner=>'RDFOWNR', network_name=>'OLS_NET');

SEM_RDFSA.APPLY_OLS_POLICYプロシージャには、他の使用可能なパラメータを指定しないでください。

トリプルレベル・セキュリティを使用する場合、ネットワークの各RDFグラフにはOLSが適用されます。つまり、ラベル・セキュリティが、関連する内部表に適用されます。

トリプルレベル・セキュリティでは、異なるラベルを持つ重複トリプルをRDFグラフに挿入できます。たとえば、次のように非常に機密性の高いラベルを持つトリプルがあるとします。

(<urn:X>,<urn:P>,<urn:Y>, "TOPSECRET")

この場合でも、権限の低い(UNCLASSIFIED)ユーザーがトリプル(<urn:X>,<urn:P>,<urn:Y>, "UNCLASSIFIED")を挿入することができます。SPARQLおよびSEM_MATCHはラベル情報を戻さないため、問合せでは両方の行が戻され(ユーザーが適切な権限を持つことが前提)、TOPSECRETトリプルとUNCLASSIFIEDトリプルを区別することは簡単ではなくなります。

RDFグラフを問い合せる際にこのようにセキュリティの低いトリプルをフィルタを使用して除外するには、SEM_MATCHで次のオプションを1つ以上使用します:

  • POLICY_NAME: OLSポリシー名を指定します。

  • MIN_LABEL: 問合せに含めるトリプルの最小限のラベルを指定します。

つまり、MIN_LABELよりも厳密に優位性が下のラベルを含むトリプルはすべて、問合せに含められません。たとえば、UNCLASSIFIEDトリプルをフィルタで除外する場合は、次の問合せを使用できます(OLSポリシー名がDEFENSEであり、問合せユーザーがUNCLASSIFIEDトリプルおよびTOPSECRETトリプルに対する読取り権限を持っていることが前提です):

SELECT s,p,y FROM table(sem_match('{?s ?p ?y}' , 
  sem_models(TEST'), null, null, null, null, 
  'MIN_LABEL=TOPSECRET POLICY_NAME=DEFENSE',
  null, null, ‘FGAC_ADMIN’, 'OLS_NET'));

前述の例のフィルタ処理は、ネイティブOLSソフトウェアによって実行されるセキュリティ・チェックに追加して発生します。

トリプルが挿入された後に、RDFグラフのアプリケーション表のCTXT1列を使用してラベル情報を表示および更新できます(ラベルを変更するためのWRITEUPおよびWRITEDOWN権限を持っていることが前提です)。

トリプルレベル・セキュリティで推論またはバルク・ロードを実行できるユーザーの制限はなく、推論またはバルク・ロードされたトリプルは、すべてユーザーのセッション行ラベルで挿入されます。SA_UTLパッケージを使用してセッション・ラベルを変更できることに注意してください。(SA_UTLの詳細は、Oracle Label Security管理者ガイドを参照してください。)

6.1.1 推論データとラダーベース推論(LBI)のファイングレイン・セキュリティ

トリプルレベル・セキュリティをOracle AI Databaseに格納されたRDFデータに対してオンにすると、表明されたファクトに、必須アクセス制御を実施するためのデータ・ラベルがタグ付けされます。また、ユーザーがSEM_APIS.CREATE_INFERRED_GRAPHプロシージャを使用して前方向チェーン・ベースの推論関数を起動すると、新しく推論された関係には現在の行ラベル(SA_UTL.NUMERIC_ROW_LABEL)がタグ付けされます。

これらの新しく推論される関係は、ユーザーがアクセスを許可されている情報のみに基づいて導出されます。ただし、これらの関係では同じデータ・ラベルが共有されます。このことは、SEM_APIS.CREATE_INFERRED_GRAPHコールが、読取り操作、論理推論計算および書込み操作の3つのステップで実行されることからわかります。読取り操作では推論計算のベースとなる情報が収集されますが、これはアクセス権限、ユーザーのラベルおよびデータ・ラベルによって制限されます。論理的推論計算のステップは完全に数学的です。伴意グラフへの推論情報の最終的な書込みは、前のステップで計算されるいくつかの新しいファクトを表明している同じユーザーと同様に行われます。

ユーザーが単一のラベルのみを所有する場合は、すべての推論された表明に単一のラベルをタグ付けすることで十分です。ユーザーが複数のラベルを持つ場合には、1つのラベルのタグ付けでは不十分です。マルチテナント状態でセットアップを行った場合によく見られる状況です。

たとえば、ユーザー・ラベルとデータ・ラベルをTopSecretと設定したユーザーが、SEM_APIS.CREATE_INFERRED_GRAPHを呼び出して、Secretという弱い方のラベルに切り替えてからSPARQL問合せを実行したと仮定します。すべての新しく推論された関係はTopSecretラベルにタグ付けされているため、この問合せを参照することはできません。ただし、ユーザーがTopSecretラベルに切り替えて戻した場合、すべての推論された関係が参照可能になります。推論された関係に関するかぎり、これは「すべてまたはゼロ」の処理です(つまり、すべて参照可能またはすべて参照不可です)。

指定ユーザーが複数のラベルを使用できる場合は、通常、異なる推論された関係に異なるラベルを割り当てます。この目的を実現する方法は2つあります。

この2つの方法のうち、ラダーベース推論(Oracle Database 12cリリース1 (12.1)で有効)の方がより単純で便利です。

SEM_APIS.CREATE_INFERRED_GRAPHの複数回の起動

DEFENSEという名前のセキュリティ・ポリシー、SCOTTという名前のユーザー、およびSCOTTが所有する一連のユーザー・ラベルLabel1、Label2、...、nがあるとします。SCOTTによる次のコールは、ラベルをLabel1として設定し、1回目の推論を実行して、新しく推論されたトリプルにLabel1をタグ付けします。

EXECUTE sa_utl.set_label('defense',char_to_label('defense','Label1'));
EXECUTE sa_utl.set_row_label('defense',char_to_label('defense','Label1'));
EXECUTE sem_apis.create_inferred_graph('inf', sem_models('contracts'), sem_rulebases('owlprime'), SEM_APIS.REACH_CLOSURE, null,'',network_owner=>'RDFOWNR',network_name=>'OLS_NET');

ここで、SCOTTはラベルをLabel2に切り替え、2回目の推論を実行し、新しく推論されたトリプルにLabel2をタグ付けします。明らかに、Label1がLabel2よりも優位である場合、Label2はLabel1が参照可能な内容以外を参照することはできないため、新しいトリプルは推論されません。Label1がLabel2よりも優位ではない場合、推論プロセスの読取りステップでは、異なるトリプル・セットを参照する可能性があるため、推論コールはいくつかの新しいトリプルを生成できます(それはLabel2がタグ付けされます)。

この例の目的上、1 <= i < j <= nという条件がtrueであること(LabeliがLabeljよりも優位ではないこと)を前提としています。

EXECUTE sa_utl.set_label('defense',char_to_label('defense','Label2'));
EXECUTE sa_utl.set_row_label('defense',char_to_label('defense','Label2'));
EXECUTE sem_apis.create_inferred_graph('inf', sem_models('contracts'), sem_rulebases('owlprime'), SEM_APIS.REACH_CLOSURE, null, 'ENTAIL_ANYWAY=T', network_owner=>'RDFOWNR', network_name=>'OLS_NET');

SCOTTは、前のアクションを、Label1、Label2、...、Labelnというラベル順序の残りのラベルで続行します。最後のステップは次のとおりです。

EXECUTE sa_utl.set_label('defense',char_to_label('defense','Labeln'));
EXECUTE sa_utl.set_row_label('defense',char_to_label('defense','Labeln'));
EXECUTE sem_apis.create_inferred_graph('inf', sem_models('contracts'), sem_rulebases('owlprime'), SEM_APIS.REACH_CLOSURE, null, 'ENTAIL_ANYWAY=T', network_owner=>'RDFOWNR', network_name=>'OLS_NET');

これらのすべてのアクションを実行すると、推論グラフは様々なラベルがタグ付けされたトリプルで構成される可能性があります。

ラダーベース推論(LBI)の使用

基本的に、1つのAPI内のラダーベース参照(LBI)ラップは、「SEM_APIS.CREATE_INFERRED_GRAPHの複数回の実行」で説明されているすべてのアクションをコールします。視覚的に、これらのアクションは、はしごを登る様子と似ています。あるラベルから次のラベルに進むと、より多くの表明されたファクトが参照可能またはアクセス可能になるため(前のラベルすべてが新しいラベルよりも優位ではない場合)、新しい関係を推論できます。

次の例に、LBIを起動する構文を示します。

EXECUTE sem_apis.create_inferred_graph('inf',
  sem_models('contracts'),
  sem_rulebases('owlprime'),
  SEM_APIS.REACH_CLOSURE,
  null,
  null,
  ols_ladder_inf_lbl_seq=>'numericLabel1 numericLabel2 numericLabel3 numericLabel4',
  network_owner=>'RDFOWNR',
  network_name=>'OLS_NET'
);

パラメータols_ladder_inf_lbl_seqでは、ラベル順序が指定されます。この順序は、数値ラベルのスペース区切りリストとして提供されます。LBIを使用する場合は、弱い方のラベルが強い方のラベルより前に配置されるように、ラベル順序を配置することをお薦めします。これは、推論されたグラフのサイズを減らすことになります。(ラベルが互いに優位ではない場合、それらはどのような順序でも指定できます。)

6.1.2 拡張例: RDFデータへのOLSトリプルレベル・セキュリティの適用

この項では、トリプルレベルのOracle Label Security (OLS)をRDFデータに適用する方法を説明する拡張例を示します。この例は非常に単純化されており、推奨のプラクティスで使用しているユーザー名およびパスワードをそのまま使用しないでください。

  1. ポリシーおよび関連する管理ユーザーを作成します。

    このステップのコード例は、同じ順序またはわずかに異なる順序で次のアクションを実行します:

    1. データベースでOLSを有効にします。
    2. SYSDBAとして接続し、セキュリティ管理ユーザーfgac_adminおよびdefense_adminを作成します。
    3. LBAC_DBAロールをfgac_adminに付与して、DEFENSE_DBAロールを作成する新しいOLS DEFENSEポリシーを作成できるようにします。
    4. DEFENSE_DBAロールをdefense_adminに付与して、ユーザーがDEFENSEポリシーにラベルを設定できるようにします。
    5. DEFENSEポリシーが適用される可能性があるデータベース・オブジェクトの対象ユーザーに適切なラベルを割り当てます。
    SQL> conn sys/<password_for_sys> as sysdba
    Connected.
    
    SQL> -- enable OLS in the database
    SQL> exec LBACSYS.configure_ols;
    
    PL/SQL procedure successfully completed.
    
    SQL> exec LBACSYS.OLS_ENFORCEMENT.enable_ols;
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- create user for security admin, grant LBAC_DBA role
    SQL> create user fgac_admin identified by <password_for_fgac_admin>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to fgac_admin;
    
    Grant succeeded.
    
    SQL> grant LBAC_DBA to fgac_admin;
    
    Grant succeeded.
    
    SQL> grant execute on sa_sysdba to fgac_admin;
    
    Grant succeeded.
    
    SQL> 
    SQL> conn fgac_admin/<password_for_fgac_admin>
    Connected.
    SQL> -- create policy DEFENSE, which creates the DEFENSE_DBA role
    SQL> EXECUTE SA_SYSDBA.CREATE_POLICY('defense','def_label');
    
    PL/SQL procedure successfully completed.
    
    SQL> select column_name from lbacsys.all_sa_policies where policy_name='DEFENSE';
    
    COLUMN_NAME
    ---------------
    DEF_LABEL
    
    1 row selected.
    
    SQL> 
    SQL> conn sys/<password_for_sys>
    Connected.
    SQL> -- create user for policy admin of the DEFENSE policy
    SQL> -- create policy admin user for the DEFENSE policy (created above)
    SQL> create user defense_admin identified by <password_for_defense_admin>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to defense_admin;
    
    Grant succeeded.
    
    SQL> grant DEFENSE_DBA to defense_admin;
    
    Grant succeeded.
    
    SQL> grant execute on sa_components to defense_admin;
    
    Grant succeeded.
    
    SQL> grant execute on sa_user_admin to defense_admin;
    
    Grant succeeded.
    
    SQL> grant execute on sa_label_admin to defense_admin;
    
    Grant succeeded.
    
    SQL> grant execute on sa_policy_admin to defense_admin;
    
    Grant succeeded.
    
    SQL> 
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> 
    SQL> BEGIN
      2    ------- create levels -------
      3    SA_COMPONENTS.CREATE_LEVEL('defense',3000,'TS','TOP SECRET');
      4    SA_COMPONENTS.CREATE_LEVEL('defense',2000,'SE','SECRET');
      5    SA_COMPONENTS.CREATE_LEVEL('defense',1000,'UN','UNCLASSIFIED');
      6  
      7    ------ create labels (using the components defined above) -------
      8    SA_LABEL_ADMIN.CREATE_LABEL('defense',1000,'UN');
      9    SA_LABEL_ADMIN.CREATE_LABEL('defense',1500,'SE');
     10    SA_LABEL_ADMIN.CREATE_LABEL('defense',3100,'TS');
     11  
     12    ------ assign default labels to users -------
     13    SA_USER_ADMIN.SET_USER_LABELS('defense', 'RDFOWNR', 'SE');
     14    SA_USER_ADMIN.SET_USER_LABELS('defense', 'A', 'UN');
     15    SA_USER_ADMIN.SET_USER_LABELS('defense', 'B', 'SE');
     16    SA_USER_ADMIN.SET_USER_LABELS('defense', 'C', 'TS');
     17    SA_USER_ADMIN.SET_USER_LABELS('defense', 'Q', 'SE');
     18  END;
     19  /
    
    PL/SQL procedure successfully completed.
  2. RDFネットワーク、RDFグラフを作成し、様々なモードでユーザーと共有します。

    このステップのコード例は、同じ順序またはわずかに異なる順序で次のアクションを実行します:

    1. SYSDBAとして接続し、rdfownrユーザー、およびabcqなど、他の複数のユーザーを作成します。
    2. rdfownrとして接続し、NET1 RDFネットワークを作成します。
    3. RDFネットワーク上の共有アクセス権をabcおよびq (問合せ専用)ユーザーに付与します。
    4. RDFネットワーク上のSA_ONLYアクセス権をdefense_adminユーザーに付与して、このネットワーク上でのみOLSのセキュリティ関連の操作を実行できるようにします。こうしても、RDFネットワークに格納されているデータへのアクセス権は付与されません。
    5. defense_adminとして接続し、RDFネットワークにDEFENSE OLSポリシー(TRIPLE_LEVEL_ONLY)を適用します。
    6. rdfownrとして接続して、PERSONという名前のRDFグラフを作成し、グラフに関するDMLおよび問合せアクセス権をユーザーabcに付与し、問合せ専用アクセス権をユーザーqに付与します。
    SQL> conn sys/<password_for_sys>
    Connected.
    
    SQL> -- create user that can be owner of RDF networks
    SQL> create user rdfownr identified by <password_for_rdfownr>;
    
    User created.
    
    SQL> grant CREATE JOB, connect, resource, unlimited tablespace to rdfownr;
    
    Grant succeeded.
    
    SQL> 
    SQL> --- create general users
    SQL> create user a identified by <password_for_a>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to a;
    
    Grant succeeded.
    
    SQL> create user b identified by <password_for_b>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to b;
    
    Grant succeeded.
    
    SQL> create user c identified by <password_for_c>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to c;
    
    Grant succeeded.
    
    SQL> create user q identified by <password_for_q>;
    
    User created.
    
    SQL> grant connect, unlimited tablespace to q;
    
    Grant succeeded.
    
    SQL> 
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> 
    SQL> -- create an RDF network and enable it for sharing with other users
    SQL> exec sem_apis.create_rdf_network('<tablespace_name>',null,network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> exec sem_apis.enable_network_sharing(network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- grant network access to a few users: full-access (they can create their own graphs) or query-only access
    SQL> EXECUTE sem_apis.enable_network_sharing('RDFOWNR', 'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> BEGIN
      2    sem_apis.grant_network_access_privs('RDFOWNR', 'NET1', 'A');
      3    sem_apis.grant_network_access_privs('RDFOWNR', 'NET1', 'B');
      4    sem_apis.grant_network_access_privs('RDFOWNR', 'NET1', 'C');
      5    sem_apis.grant_network_access_privs('RDFOWNR', 'NET1', 'Q', options=>' QUERY_ONLY=T ');
      6  END;
      7  /
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- share in SA_ONLY=T mode with policy admin user (note: this sharing mode provides no visibility to RDF data)
    SQL> exec sem_apis.grant_network_access_privs('rdfownr', 'NET1', 'DEFENSE_ADMIN', options=>' SA_ONLY=T ');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- tables in RDF network are not visible to security and policy admin users (EXCEPT when managing security policies on them)
    SQL> conn fgac_admin/<password_for_fgac_admin>
    Connected.
    SQL> select table_name from SYS.all_tables where table_name LIKE 'NET1#RDF%' order by 1;
    
    no rows selected
    
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> select table_name from SYS.all_tables where table_name LIKE 'NET1#RDF%' order by 1;
    
    no rows selected
    
    SQL> 
    SQL> -- APPLY_OLS_POLICY on the RDF network
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> exec sem_rdfsa.apply_ols_policy('defense', sem_rdfsa.TRIPLE_LEVEL_ONLY,network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- after APPLY_OLS_POLICY: a new column gets added to RDF_VALUE$ table and to RDF_LINK$ table
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> select table_name, column_name, data_type from sys.user_tab_columns where table_name IN ('NET1#RDF_VALUE$', 'NET1#RDF_LINK$') and column_name='DEF_LABEL' order by 1;
    
    TABLE_NAME                     COLUMN_NAME     DATA_TYPE
    ------------------------------ --------------- ----------
    NET1#RDF_LINK$                 DEF_LABEL       NUMBER
    
    1 row selected.
    
    SQL> 
    SQL> -- disable the OLS policy and set the label for all the pre-existing values to the lowest label
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> exec sem_rdfsa.disable_ols_policy(network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> -- re-enable the OLS policy and verify that the values are visible to all (EXCEPT security and policy admin users)
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> exec sem_rdfsa.enable_ols_policy(network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> -- create an RDF graph (owned by rdfownr)
    SQL> exec sem_apis.create_rdf_graph('PERSON',null,null,network_owner=>'rdfownr',network_name=>'NET1');
    
    PL/SQL procedure successfully completed.
    
    SQL> -- the corr. RDFT view, used as target for DML operations for this graph, has the extra label column
    SQL> desc NET1#RDFT_PERSON
     Name                                                                                                              Null?    Type
     ----------------------------------------------------------------------------------------------------------------- -------- ----------------------------------------------------------------------------
     TRIPLE                                                                                                                     MDSYS.SDO_RDF_TRIPLE_S
     DEF_LABEL                                                                                                                  NUMBER
    
    SQL> -- the corr. RDFM view, used as source for query processing for this graph, has the extra column
    SQL> desc NET1#RDFM_PERSON
     Name                                                                                                              Null?    Type
     ----------------------------------------------------------------------------------------------------------------- -------- ----------------------------------------------------------------------------
     P_VALUE_ID                                                                                                        NOT NULL NUMBER
     START_NODE_ID                                                                                                              NUMBER
     CANON_END_NODE_ID                                                                                                          NUMBER
     END_NODE_ID                                                                                                                NUMBER
     MODEL_ID                                                                                                                   NUMBER
     COST                                                                                                                       NUMBER
     DEF_LABEL                                                                                                                  NUMBER
     CTXT2                                                                                                                      VARCHAR2(4000)
     DISTANCE                                                                                                                   NUMBER
     EXPLAIN                                                                                                                    VARCHAR2(4000)
     PATH                                                                                                                       VARCHAR2(4000)
     G_ID                                                                                                                       NUMBER
     LINK_ID                                                                                                                    VARCHAR2(89)
    
    SQL> 
    SQL> -- share access to the above graph with users who already have shared access to network (Note: user Q is given query-only access)
    SQL> BEGIN
      2    sem_apis.grant_model_access_privs('PERSON','a',sys.odcivarchar2list('INSERT','UPDATE','DELETE','SELECT','QUERY'),network_owner=>'rdfownr',network_name=>'NET1');
      3    sem_apis.grant_model_access_privs('PERSON','b',sys.odcivarchar2list('INSERT','UPDATE','DELETE','SELECT','QUERY'),network_owner=>'rdfownr',network_name=>'NET1');
      4    sem_apis.grant_model_access_privs('PERSON','c',sys.odcivarchar2list('INSERT','UPDATE','DELETE','SELECT','QUERY'),network_owner=>'rdfownr',network_name=>'NET1');
      5    sem_apis.grant_model_access_privs('PERSON','q',sys.odcivarchar2list('QUERY'),network_owner=>'rdfownr',network_name=>'NET1');
      6  END;
      7  /
    
    PL/SQL procedure successfully completed.
  3. 例に使用するユーティリティ関数とビューを設定します。

    次のコードで、ユーティリティ・ビューTRIPLES_VIEWおよびVALUES_VIEWを作成します。これらは、ユーザーが表示できるトリプルと値の簡易ビューを、関連するOLSのラベルとともに返します。特定のidの値が見つからない場合は、id自体が返されますが、先頭にアスタリスクが付きます。

    SQL> create or replace function shortval (val_id number) return varchar2 as
      2    shval varchar2(100);
      3  begin
      4    select NVL(vname_suffix, vname_prefix) into shval from rdfownr.net1#rdf_value$ where value_id = val_id and rownum < 2;
      5    return substr(shval,1,20);
      6  exception
      7    when no_data_found then
      8      return '*' || val_id;
      9  end;
     10  /
    Function created.
    
    SQL> grant execute on shortval to public;
    Grant succeeded.
    
    SQL> create or replace view triples_view as
      2  select rdfownr.shortval(t.triple.rdf_s_id) subj, rdfownr.shortval(t.triple.rdf_p_id) pred, rdfownr.shortval(t.triple.rdf_c_id) obj, def_label
      3  from rdfownr.NET1#RDFT_PERSON t;
    View created.
     
    SQL> grant read on triples_view to public;
    Grant succeeded.
    
    SQL> create or replace view values_view as
      2  select value_id, value_name
      3  from rdfownr.net1#rdf_value$
      4  where (value_name NOT LIKE '%rdf%' and value_name NOT LIKE '%owl%' and canon_id is NULL);
    View created.
    
    SQL> grant read on values_view to public;
    Grant succeeded.
  4. RDFグラフに対してSQLのInsertを使用する際には、ファイングレイン・アクセス制御(FGAC)を設定します。

    ユーザーに割り当てられたラベルによって、ユーザーが挿入したデータに関連付けることができるラベルが決まります。これは、ユーザーに割り当てられたラベル、またはユーザーのラベルよりも優位性が下の任意のラベルになります。また、割り当てられたラベルによって、このような表のどのデータがユーザーに表示されるかが決まります。

    SQL> --
    SQL> -- INSERT using SQL Insert statement
    SQL> --
    SQL> 
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> 
    SQL> -- 1) use default label, which is 'SE::' or 1500 for rdfownr, for the triple as well as the values
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple) values (sdo_rdf_triple_s('person',
      2  '<urn:john>','<urn:spouseOf>','<urn:mary>',
      3  'rdfownr','NET1'));
    
    1 row created.
    
    SQL> COMMIT;
    
    Commit complete.
    
    SQL> 
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    john                   spouseOf               mary                   1500
    
    1 row selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    urn:john
    urn:mary
    urn:spouseOf
    
    3 rows selected.
    
    SQL> 
    SQL> conn c/<password_for_c>
    Connected.
    SQL> -- 2) use default explicit label 'UN::' (1000) for the triple
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple, def_label) values (sdo_rdf_triple_s('person',
      2  '<urn:john>','<urn:secretId>','"jasmin#*!@"',
      3  'rdfownr','NET1'), char_to_label('DEFENSE', 'UN::'));
    
    1 row created.
    
    SQL> COMMIT;
    
    Commit complete.
    
    SQL> 
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1500
    
    2 rows selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    jasmin#*!@
    urn:john
    urn:mary
    urn:secretId
    urn:spouseOf
    
    5 rows selected.
    
    SQL> 
    SQL> conn a/<password_for_a>1
    Connected.
    SQL> -- 3) use default label, which is 'UN::' or 1000 for user A, for the triple
    SQL> -- this triple already exists, but with a higher label (1500) and hence not visible to the current user: so, a duplicate triple gets inserted
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple) values (sdo_rdf_triple_s('person',
      2  '<urn:john>','<urn:spouseOf>','<urn:mary>',
      3  'rdfownr','NET1'));
    
    1 row created.
    
    SQL> 
    SQL> -- 4) use default label ('UN::' or 1000) for the triple
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple) values (sdo_rdf_triple_s('person',
      2  '<urn:childOf>','owl:inverseOf','<urn:parentOf>',
      3  'rdfownr','NET1'));
    
    1 row created.
    
    SQL> COMMIT;
    
    Commit complete.
    
    SQL> 
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000
    
    3 rows selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    jasmin#*!@
    urn:childOf
    urn:john
    urn:mary
    urn:parentOf
    urn:secretId
    urn:spouseOf
    
    7 rows selected.
    
    SQL> 
    SQL> conn b/<password_for_b>
    Connected.
    SQL> -- 5) use default label ('SE::' or 1500) for triple
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple) values (sdo_rdf_triple_s('person',
      2  '<urn:spouseOf>','rdf:type','owl:SymmetricProperty',
      3  'rdfownr','NET1'));
    
    1 row created.
    
    SQL> 
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    4 rows selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    jasmin#*!@
    urn:childOf
    urn:john
    urn:mary
    urn:parentOf
    urn:secretId
    urn:spouseOf
    
    7 rows selected.
    
    SQL> 
    SQL> conn c/<password_for_c>
    Connected.
    SQL> -- 6) use default label ('TS::' or 3100) for the triple
    SQL> INSERT INTO rdfownr.NET1#RDFT_PERSON(triple) values (sdo_rdf_triple_s('person',
      2  '<urn:john>','<urn:childOf>','<urn:bob>',
      3  'rdfownr','NET1'));
    
    1 row created.
    
    SQL> COMMIT;
    
    Commit complete.
    
    SQL> 
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   childOf                bob                    3100
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    5 rows selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    jasmin#*!@
    urn:bob
    urn:childOf
    urn:john
    urn:mary
    urn:parentOf
    urn:secretId
    urn:spouseOf
    
    8 rows selected.
  5. 指定されたラベル・シーケンスに対して繰り返し反復処理を実行することにより、ラベルベースの推論を実行します。

    次のコードは、ラベル・シーケンス<1000, 1500, 3100>のラベルベースの推論を示しています。導出されたトリプルは、それなしでは導出できない最初期の(minimum)ラベルでマークされます。たとえば、導出されたトリプルbob parentOf johnには3100 ('TS::')というラベルが付きます。これは、ユーザーに少なくとも3100のラベルがある場合にのみjohn childOf bobが表示されるため、3100より下位のラベルでは導出できないからです。

    SQL> conn sys/<password_for_sys> as sysdba
    Connected.
    
    SQL> -- allow "exchange partition" operations used during inference
    SQL> grant EXEMPT ACCESS POLICY on schema rdfownr to rdfownr;
    Grant succeeded.
    
    SQL> conn c/<password_for_c>
    Connected.
    
    SQL> BEGIN
      2   sem_apis.create_inferred_graph('inf',
      3    sem_models('PERSON'),
      4    sem_rulebases('OWL2RL'),
      5    SEM_APIS.REACH_CLOSURE,
      6    null,
      7    null,
      8    ols_ladder_inf_lbl_seq=>'1000 1500 3100',
      9    network_owner=>'RDFOWNR',
     10    network_name=>'NET1'
     11  );
     12  END;
     13  /
    
    PL/SQL procedure successfully completed.
    
    SQL> conn sys/<password_for_sys> as sysdba
    Connected.
    
    SQL> -- "exchange partition" operations not needed any more
    SQL> revoke EXEMPT ACCESS POLICY on schema rdfownr from rdfownr;
    Revoke succeeded.
    
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    
    SQL> create or replace view inf_triples_view as
      2  select rdfownr.shortval(t.start_node_id) subj, rdfownr.shortval(t.p_value_id) pred, rdfownr.shortval(canon_end_node_id) obj, def_label
      3  from rdfownr.NET1#RDFI_INF t;
    View created.
    
    SQL> grant read on inf_triples_view to public;
    Grant succeeded.
    
    SQL> conn c/<password_for_c>
    Connected.
    
    SQL> -- check labels for the visible triples and values
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    bob                    parentOf               john                   3100
    mary                   spouseOf               john                   1500
    parentOf               inverseOf              childOf                1000
    spouseOf               inverseOf              spouseOf               1500
    
    4 rows selected.
    
    SQL> select value_name from rdfownr.values_view order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    1
    jasmin#*!@
    true
    urn:bob
    urn:childOf
    urn:john
    urn:mary
    urn:parentOf
    urn:secretId
    urn:spouseOf
    
    10 rows selected.
    
    SQL> 
    SQL> -- visibility note: users with lower label may sometimes be able to see a triple but not the higher-labeled values used in that triple
    SQL> conn a/<password_for_a>
    Connected.
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000
    
    3 rows selected.
    
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    parentOf               inverseOf              childOf                1000
    
    1 row selected.
    
    SQL> conn b/<password_for_b>
    Connected.
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    4 rows selected.
    
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    mary                   spouseOf               john                   1500
    parentOf               inverseOf              childOf                1000
    spouseOf               inverseOf              spouseOf               1500
    
    3 rows selected.
    
    SQL> conn c/<password_for_c>
    Connected.
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   childOf                bob                    3100
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    5 rows selected.
    
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    bob                    parentOf               john                   3100
    mary                   spouseOf               john                   1500
    parentOf               inverseOf              childOf                1000
    spouseOf               inverseOf              spouseOf               1500
    
    4 rows selected.
    
    SQL> conn q/<password_for_q>
    Connected.
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    4 rows selected.
    
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    mary                   spouseOf               john                   1500
    parentOf               inverseOf              childOf                1000
    spouseOf               inverseOf              spouseOf               1500
    
    3 rows selected.
    
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    4 rows selected.
    
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.inf_triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    mary                   spouseOf               john                   1500
    parentOf               inverseOf              childOf                1000
    spouseOf               inverseOf              spouseOf               1500
    
    3 rows selected.
  6. ラベル関数を定義して使用します。

    次のコードは、述語が<urn:salary>の場合に上位ラベル('SE::')をトリプルに関連付け、それ以外の場合は下位ラベル('UN::')を関連付けるラベル関数を、バルクロード時に使用する例を示しています。

    SQL> -- use of label functions and its use during bulk-load 
    SQL> conn sys/<password_for_sys>
    Connected.
    SQL> grant execute on to_lbac_data_label to rdfownr;
    
    Grant succeeded.
    
    SQL> 
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> 
    SQL> CREATE TABLE stage_table (
      2                       RDF$STC_sub varchar2(4000) not null,
      3                       RDF$STC_pred varchar2(4000) not null,
      4                       RDF$STC_obj varchar2(4000) not null
      5  );
    
    Table created.
    
    SQL> 
    SQL> insert into stage_table values ('<urn:john>','<urn:lastName>','"Smith"');
    
    1 row created.
    
    SQL> insert into stage_table values ('<urn:john>','<urn:salary>','"100K"');
    
    1 row created.
    
    SQL> commit;
    
    Commit complete.
    
    SQL> 
    SQL> -- define a label function for generating label for a given triple
    SQL> -- label function for generating labels for triples (in RDF_LINK$)
    SQL> CREATE OR REPLACE FUNCTION gen_triple_label_on_pid (p_value_id number) Return LBACSYS.LBAC_LABEL
      2  as
      3    i_label varchar2(80);
      4    vty varchar2(10);
      5    vnm varchar2(100);
      6  BEGIN
      7    select value_type, value_name into vty, vnm from rdfownr.net1#rdf_value$ where value_id=p_value_id;
      8    if (vty = 'UR' and vnm = 'urn:salary') then
      9      i_label := 'SE::';
     10    else
     11      i_label := 'UN::';
     12    end if;
     13    RETURN TO_LBAC_DATA_LABEL('DEFENSE',i_label);
     14  END;
     15  /
    
    Function created.
    
    SQL> 
    SQL> grant execute on gen_triple_label_on_pid to LBAC_TRIGGER;
    
    Grant succeeded.
    
    SQL> 
    SQL> -- ALTER_OLS_TABLE_POLICY to include use of label function for triples
    SQL> conn defense_admin/<password_for_defense_admin>
    Connected.
    SQL> exec sem_rdfsa.alter_ols_table_policy('triple', 'label_function', 'rdfownr.gen_triple_label_on_pid(:new.p_value_id)', network_owner=>'rdfownr',network_name=>'net1');
    
    PL/SQL procedure successfully completed.
    
    SQL> select * from lbacsys.all_sa_table_policies where schema_name='RDFOWNR' order by policy_name, table_name;
    
    POLICY_NAM SCHEMA_NAME                                                                                                                      TABLE_NAME                     STATUS
    ---------- -------------------------------------------------------------------------------------------------------------------------------- ------------------------------ --------
    TABLE_OPTIONS
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    FUNCTION
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    PREDICATE
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    DEFENSE    RDFOWNR                                                                                                                          NET1#RDF_LINK$                 ENABLED
    READ_CONTROL, INSERT_CONTROL, UPDATE_CONTROL, DELETE_CONTROL, LABEL_DEFAULT, LABEL_UPDATE, CHECK_CONTROL
    rdfownr.gen_triple_label_on_pid(:new.p_value_id)
    
    
    
    1 row selected.
    
    SQL> 
    SQL> -- bulk-load uses designated label function to mark the salary triple as 'SE::' (1500) while marking the "lastName" triples as 'UN::' (1000)
    SQL> conn rdfownr/<password_for_rdfownr>
    Connected.
    SQL> exec sem_apis.bulk_load_from_staging_table('person','rdfownr','stage_table',network_owner=>'rdfownr',network_name=>'net1');
    
    PL/SQL procedure successfully completed.
    
    SQL> 
    SQL> select subj, pred, obj, listagg(def_label,', ') within group (order by def_label) labels from rdfownr.triples_view group by subj, pred, obj order by 1,2,3;
    
    SUBJ                   PRED                   OBJ                    LABELS
    ---------------------- ---------------------- ---------------------- ------------------------------
    childOf                inverseOf              parentOf               1000
    john                   lastName               Smith                  1000
    john                   salary                 100K                   1500
    john                   secretId               jasmin#*!@             1000
    john                   spouseOf               mary                   1000, 1500
    spouseOf               type                   SymmetricProperty      1500
    
    6 rows selected.
    
    SQL> select value_name from rdfownr.values_view group by value_name order by 1;
    
    VALUE_NAME
    -----------------------------------------------------------------
    1
    100K
    Smith
    jasmin#*!@
    true
    urn:bob
    urn:childOf
    urn:john
    urn:lastName
    urn:mary
    urn:parentOf
    urn:salary
    urn:secretId
    urn:spouseOf
    
    14 rows selected.