6.1 Triple-Level Security
The triple-level security option provides a thin layer of RDF-specific capabilities on top of Oracle AI Database native support for label security.
To use triple-level security, specify SEM_RDFSA.TRIPLE_LEVEL_ONLY
as the rdfsa_options
parameter value when you execute the SEM_RDFSA.APPLY_OLS_POLICY procedure. For example:
EXECUTE sem_rdfsa.apply_ols_policy('defense', SEM_RDFSA.TRIPLE_LEVEL_ONLY, network_owner=>'RDFOWNR', network_name=>'OLS_NET');
Ensure, you do not specify any of the other available parameters for the SEM_RDFSA.APPLY_OLS_POLICY procedure.
When you use triple-level security, OLS is applied to each RDF graph in the network. That is, label security is applied to the relevant internal tables.
With triple-level security, duplicate triples with different labels can be inserted in the RDF graph. For example, assume that you have a triple with a very sensitive label, such as:
(<urn:X>,<urn:P>,<urn:Y>, "TOPSECRET")
This does not prevent a low-privileged (UNCLASSIFIED
) user from inserting the triple (<urn:X>,<urn:P>,<urn:Y>, "UNCLASSIFIED")
. Because SPARQL and SEM_MATCH do not return label information, a query will return both rows (assuming the user has appropriate privileges), and it will not be easy to distinguish between the TOPSECRET
and UNCLASSIFIED
triples.
To filter out such low-security triples when querying the RDF graphs, you can use one or more of the following options with SEM_MATCH:
-
POLICY_NAME
specifies the OLS policy name. -
MIN_LABEL
specifies the minimum label for triples that are included in the query.
In other words, every triple that contains a label that is strictly dominated by
MIN_LABEL
is not included in the query. For example, to filter out the
UNCLASSIFIED
triple, you could use the following query (assuming the OLS
policy name is DEFENSE
and that the query user has read privileges over
UNCLASSIFIED
and TOPSECRET
triples):
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'));
Note that the filtering in the preceding example occurs in addition to the security checks performed by the native OLS software.
After a triple has been inserted, you can view and update the label information
through the CTXT1
column in the application table for the RDF graph (assuming
that you have the WRITEUP
and WRITEDOWN
privileges to modify
the labels).
There are no restrictions on who can perform inference or bulk loading with triple-level security; all of the inferred or bulk loaded triples are inserted with the user's session row label. Note that you can change the session labels by using the SA_UTL package. (For more information about SA_UTL, see Oracle Label Security Administrator's Guide.)
- Fine-Grained Security for Inferred Data and Ladder-Based Inference (LBI)
- Extended Example: Applying OLS Triple-Level Security on RDF Data
Parent topic: Fine-Grained Access Control for RDF Data
6.1.1 Fine-Grained Security for Inferred Data and Ladder-Based Inference (LBI)
When triple-level security is turned on for RDF data stored in Oracle AI Database, asserted facts are tagged with data labels
to enforce mandatory access control. In addition, when a user invokes the forward-chaining
based inference function through the SEM_APIS.CREATE_INFERRED_GRAPH procedure, the newly inferred relationships will be tagged with the current
row label (SA_UTL.NUMERIC_ROW_LABEL
).
These newly inferred relationships are derived solely based on the information that the user is allowed to access. These relationships do, however, share the same data label. This is understandable because a SEM_APIS.CREATE_INFERRED_GRAPH call can be viewed as a three-step process: read operation, followed by a logical inference computation, followed by a write operation. The read operation gathers information upon which inference computation is based, and it is restricted by access privileges, the user's label, and the data labels; the logical inference computation step is purely mathematical; and the final write of inferred information into the entailed graph is no different from the same user asserting some new facts (which happen to be calculated by the previous step).
Having all inferred assertions tagged with a single label is sufficient if a user only owns a single label. It is, however, not fine-grained enough when there are multiple labels owned by the same user, which is a common situation in a multitenancy setup.
For example, assume a user sets its user label and data label as
TopSecret
, invokes SEM_APIS.CREATE_INFERRED_GRAPH, switches to a weaker label named Secret
, and finally performs a SPARQL
query. The query will not be able to see any of those newly inferred relationships because
they were all tagged with the TopSecret
label. However, if the user switches
back to the TopSecret
label, now every single inferred relationship is
visible. It is "all or nothing" (that is, all visible or nothing visible) as far as inferred
relationships are concerned.
When multiple labels are available for use by a given user, you normally want to assign different labels to different inferred relationships. There are two ways to achieve this goal:
Ladder-based inference, effective with Oracle Database 12c Release 1 (12.1), is probably the simpler and more convenient of the two approaches.
Invoking SEM_APIS.CREATE_INFERRED_GRAPH Multiple Times
Assume a security policy named DEFENSE, a user named SCOTT, and a sequence of user labels Label1, Label2, ..., Labeln owned by SCOTT. The following call by SCOTT sets the label as Label1, runs the inference for the first time, and tags the newly inferred triples with 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');
Now, SCOTT switches the label to Label2, runs the inference a second time, and tags the newly inferred triples with Label2. Obviously, if Label2 is dominated by Label1, then no new triples will be inferred because Label2 cannot see anything beyond what Label1 is allowed to see. If Label2 is not dominated by Label1, the read step of the inference process will probably see a different set of triples, and consequently the inference call can produce some new triples, which will in turn be tagged with Label2.
For the purpose of this example, assume the following condition holds true: for any 1 <= i < j <= n, Labelj is not dominated by Labeli.
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 continues the preceding actions using the rest of the labels in the label sequence: Label1, Label2, ..., Labeln. The last step will be as follows:
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');
After all these actions are performed, the inference graph probably consists of triples tagged with various different labels.
Using Ladder-Based Inference (LBI)
Basically, ladder-based inference (LBI) wraps in one API call all the actions described in the Invoking SEM_APIS.CREATE_INFERRED_GRAPH Multiple Times approach. Visually, those actions are like climbing up a ladder. When proceeding from one label to the next, more asserted facts become visible or accessible (assuming the new label is not dominated by any of the previous ones), and therefore new relationships can be inferred.
The syntax to invoke LBI is shown in the following example.
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' );
The parameter ols_ladder_inf_lbl_seq
specifies a sequence of labels. This sequence is provided as a list of numeric labels delimited by spaces. When using LBI, it is a good practice to arrange the sequence of labels so that weaker labels are put before stronger labels. This will reduce the size of the inferred graph. (If labels do not dominate each other, they can be specified in any order.)
Parent topic: Triple-Level Security
6.1.2 Extended Example: Applying OLS Triple-Level Security on RDF Data
This section presents an extended example illustrating how to apply triple-level Oracle Label Security (OLS) to RDF data. The examples are very simplified, and do not reflect recommended practices regarding user names and passwords.
- Create the policy and related administrative users.
The code example in this step performs the following actions in the same or slightly different order:
- Enable OLS in the database.
- Connect as
SYSDBA
to create security admin users:fgac_admin
anddefense_admin
. - Grant the
LBAC_DBA
role tofgac_admin
to allow the creation of a new OLSDEFENSE
policy which creates theDEFENSE_DBA
role. - Grant the
DEFENSE_DBA
role todefense_admin
enabling users to set up the labels for theDEFENSE
policy. - Assign the appropriate labels to the intended users of the database
objects to which the
DEFENSE
policy may be applied.
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.
- Create an RDF network, RDF graph, and share it with users in various modes.
The code example in this step performs the following actions in the same or slightly different order:
- Connect as
SYSDBA
to create therdfownr
user and several other users such asa
,b
,c
, andq
. - Connect as
rdfownr
to create theNET1
RDF network. - Granting shared access on the RDF network to
a
,b
,c
, andq
(query-only) users. - Grant
SA_ONLY
access on the RDF network to thedefense_admin
user enabling them to perform OLS security related operations on the network only. This does not grant access to the data stored in the RDF network. - Connect as
defense_admin
and apply theDEFENSE
OLS policy (TRIPLE_LEVEL_ONLY
) on the RDF network. - Connect as
rdfownr
to create an RDF graph namedPERSON
and grant DML and query access on the graph to usersa
,b
,c
, and query-only access to userq
.
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.
- Connect as
- Set up utility functions and views used for illustration purposes.
The following code creates the utility views,
TRIPLES_VIEW
andVALUES_VIEW
. These return a simplified view of the triples and values, along with the relevant OLS labels, that are visible to the user. If a value is not found for a givenid
, it returns theid
itself but prefixed with an asterisk.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.
- Set Fine Grained Access Control (FGAC) when using SQL Insert into RDF graphs.
Note that the label assigned to a user determines what labels can be associated with the data inserted by the user. It could be the label assigned to the user or any label that is dominated by the user's label. The assigned label also determines what data from such a table is visible to the user.
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.
- Perform label-based inference by iterating repeatedly over the given sequence
of labels.
The following code shows label-based inference with the label sequence
<1000, 1500, 3100>
. A derived triple is marked with the earliest (minimum
) label without which it cannot be derived. For example, the derived triplebob parentOf john
will have the3100 ('TS::')
label because it cannot be derived with any label below3100
asjohn childOf bob
is only visible when user has label of at least3100
.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.
- Define and use label functions.
The following code shows bulkload-time use of a label function that associates a higher label (
'SE::'
) with a triple when the predicate is<urn:salary>
and a lower label ('UN::'
) otherwise.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.
Parent topic: Triple-Level Security