14.2.4 User Authentication and Authorization

The Oracle Graph server (PGX) uses an Oracle Database as identity manager. Both username and password based as well as Kerberos based authentication is supported.

The actions that you are allowed to do on the graph server are determined by the privileges enabled by roles that have been granted to you in the Oracle Database.

14.2.4.1 Basic Steps for Using an Oracle Database for Authentication

You can follow the steps explained in this section to authenticate users to the graph server (PGX).

  1. Use an Oracle Database version that is supported by Oracle Graph Server and Client: version 12.2 or later, including Autonomous Database.
  2. Ensure that you have SYSDBA access for your database (or ADMIN access for autonomous databases) to grant and revoke users access to the graph server (PGX).
  3. Ensure that all existing users to which you plan to grant access to the graph server have at least the following privileges granted.
    CREATE SESSION, CREATE TABLE
  4. Ensure that the database is accessible through JDBC from the host where the graph server runs.
  5. As SYSDBA (or ADMIN on autonomous databases), run the following procedure to create the roles required by the graph server.

    Note:

    If you are using an Autonomous Database Serverless instance, or if your on-premises Oracle Database version is 23ai, then you can skip this step as these roles are pre-installed.
     -- This procedure creates a list of roles needed for graph.
      DECLARE
        PRAGMA AUTONOMOUS_TRANSACTION;
        role_exists EXCEPTION;
        PRAGMA EXCEPTION_INIT(role_exists, -01921);
        TYPE graph_roles_table IS TABLE OF VARCHAR2(50);
        graph_roles graph_roles_table;
      BEGIN
        graph_roles := graph_roles_table(
          'GRAPH_DEVELOPER',
          'GRAPH_ADMINISTRATOR',
          'GRAPH_USER',
          'PGX_SESSION_CREATE',
          'PGX_SERVER_GET_INFO',
          'PGX_SERVER_MANAGE',
          'PGX_SESSION_READ_MODEL',
          'PGX_SESSION_MODIFY_MODEL',
          'PGX_SESSION_NEW_GRAPH',
          'PGX_SESSION_GET_PUBLISHED_GRAPH',
          'PGX_SESSION_COMPILE_ALGORITHM',
          'PGX_SESSION_ADD_PUBLISHED_GRAPH');
        FOR elem IN 1 .. graph_roles.count LOOP
          BEGIN
            dbms_output.put_line('create_graph_roles: ' || elem || ': CREATE ROLE ' || graph_roles(elem));
            EXECUTE IMMEDIATE 'CREATE ROLE ' || graph_roles(elem);
          EXCEPTION
            WHEN role_exists THEN
              dbms_output.put_line('create_graph_roles: role already exists. continue');
            WHEN OTHERS THEN
              RAISE;
          END;
        END LOOP;
      EXCEPTION
        when others then
          dbms_output.put_line('create_graph_roles: hit error ');
          raise;
      END;
      /

    Optionally, this procedure is also available in /opt/oracle/graph/scripts/create_graph_roles.sql.

    See Table 14-4 for more information on the roles.
  6. Assign default permissions to the roles GRAPH_DEVELOPER, GRAPH_USER and GRAPH_ADMINISTRATOR to group multiple permissions together.

    Note:

    If you are using an Autonomous Database serverless instance, or if your on-premises Oracle Database version is 23ai, then you can skip this step as these privileges are available by default.
    -- This procedure add some grants to the graph roles.
      DECLARE
        PRAGMA AUTONOMOUS_TRANSACTION;
      BEGIN
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_CREATE TO GRAPH_ADMINISTRATOR';
        EXECUTE IMMEDIATE 'GRANT PGX_SERVER_GET_INFO TO GRAPH_ADMINISTRATOR';
        EXECUTE IMMEDIATE 'GRANT PGX_SERVER_MANAGE TO GRAPH_ADMINISTRATOR';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_CREATE TO GRAPH_DEVELOPER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_NEW_GRAPH TO GRAPH_DEVELOPER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_GET_PUBLISHED_GRAPH TO GRAPH_DEVELOPER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_MODIFY_MODEL TO GRAPH_DEVELOPER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_READ_MODEL TO GRAPH_DEVELOPER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_CREATE TO GRAPH_USER';
        EXECUTE IMMEDIATE 'GRANT PGX_SESSION_GET_PUBLISHED_GRAPH TO GRAPH_USER';
        BEGIN
          EXECUTE IMMEDIATE 'GRANT CREATE PROPERTY GRAPH TO GRAPH_DEVELOPER';
        EXCEPTION WHEN others then
          if sqlcode = -990 then
            mdsys.opg_log.debug('grant create property graph to graph_developer: missing privilege, continue');
          else
            raise;
          end if;
        END;
      EXCEPTION
        when others then
          dbms_output.put_line('add_graph_roles_grants: hit error ');
          raise;
      END;
      /

    Optionally, this procedure is also available in /opt/oracle/graph/scripts/create_graph_roles.sql.

  7. Assign roles to all the database developers who should have access to the graph server (PGX). For example:
    GRANT GRAPH_DEVELOPER TO <graphuser>

    where <graphuser> is a user in the database. You can also assign individual permissions (roles prefixed with PGX_) to users directly.

  8. Assign the administrator role to users who should have administrative access. For example:
    GRANT GRAPH_ADMINISTRATOR to <administratoruser>

    where <administratoruser> is a user in the database.

14.2.4.1.1 Privileges and Roles in Oracle Database

This section describes the database roles and privileges that are required only if you are using the graph server (PGX).

Table 14-4 Oracle Database Privileges and Roles Required for Using the Graph Server (PGX)

Role Operations enabled by this role Used By
PGX_SESSION_CREATE Create a new PGX session using the ServerInstance.createSession API. Graph developers and graph users
PGX_SERVER_GET_INFO Get status information on the PGX instance using the Admin API. Users who administer PGX
PGX_SERVER_MANAGE (includes PGX_SERVER_GET_INFO) Manage the PGX instance using the Admin API to stop or restart PGX. Users who administer PGX
PGX_SESSION_NEW_GRAPH Create a new graph in PGX by loading from the database using a config file, using the CREATE PROPERTY GRAPH statement in PGQL, creating a sub-graph from another graph, or using the GraphBuilder. Graph developers and graph users
PGX_SESSION_GET_PUBLISHED_GRAPH Query and view graphs published by another user to the public namespace. Graph developers and graph users
PGX_SESSION_ADD_PUBLISHED_GRAPH (includes PGX_SESSION_GET_PUBLISHED_GRAPH) Publish a graph to the public namespace. Graph developers
PGX_SESSION_COMPILE_ALGORITHM Compile an algorithm using the PGX Algorithm API. Graph developers
PGX_SESSION_READ_MODEL Load and use an ML model using PgxML. Graph developers
PGX_SESSION_MODIFY_MODEL Create, train, and store an ML model using PgxML. Graph developers

Few additional roles are also created to group multiple roles together. They provide a convenient way to grant multiple roles to database users. See Mapping Graph Server Roles to Default Privileges for more information on these additional roles.

You can create additional groups that are useful for your application, as described in Adding and Removing Roles and Defining Permissions for Individual Users.

14.2.4.2 Prepare the Graph Server for Database Authentication

Locate the pgx.conf file of your installation.

If you installed the graph server via RPM, the file is located at: /etc/oracle/graph/pgx.conf

If you use the webapps package to deploy into Tomcat or WebLogic Server, the pgx.conf file is located inside the web application archive file (WAR file) at: WEB-INF/classes/pgx.conf

Tip: On Linux, you can use vim to edit the file directly inside the WAR file without unzipping it first. For example:
vim graph-server-webapp-<version>.war

Inside the pgx.conf file, locate the jdbc_url line of the realm options:

...
"pgx_realm": {
  "implementation": "oracle.pg.identity.DatabaseRealm",
  "options": {
    "jdbc_url": "<REPLACE-WITH-DATABASE-URL-TO-USE-FOR-AUTHENTICATION>",
    "token_expiration_seconds": 3600,
...

Replace the text with the JDBC URL pointing to your database that you configured in the previous step. For example:

...
"pgx_realm": {
  "implementation": "oracle.pg.identity.DatabaseRealm",
  "options": {
    "jdbc_url": "jdbc:oracle:thin:@myhost:1521/myservice",
    "token_expiration_seconds": 3600,
...

Then, start the graph server by running the following command as a root user or with sudo:

sudo systemctl start pgx

Preparing the Graph Server (PGX) to Connect to Autonomous Database

You can configure your graph server(PGX) to connect to an Autonomous Database instance.

Irrespective of whether your graph server (PGX) instance is running on premises or on Oracle Cloud Infrastructure (OCI), you can perform the following steps to determine the service name to connect to your Autonomous Database instance and update the JDBC URL in /etc/oracle/graph/pgx.conf file.

  1. Download and save the wallet for your Autonomous Database instance from the Oracle Cloud Infrastructure (OCI) Console. See Download Client Credentials (Wallets) for more information.
  2. Unzip the wallet to a new subdirectory in /etc/oracle/graph/wallets/<dbname>, and change the group permission as shown:
    sudo unzip Wallet_<dbname>.zip -d /etc/oracle/graph/wallets/<dbname>
    sudo chgrp -R oraclegraph /etc/oracle/graph/wallets/<dbname>
  3. Determine the connect identifier from the tnsnames.ora file in /etc/oracle/graph/wallets/<dbname> directory. For example, the entry must be similar to:
    graphdb_low = 
        description= (retry_count=20)(retry_delay=3)
            (address=
                (protocol=tcps)(port=1522)
                (host=adwc.example.oraclecloud.com)
            )
            (connect_data=(service_name=graphdb_low.adwc.oraclecloud.com))
            (security=(ssl_server_cert_dn="CN=adwc.example.oraclecloud.com, OU=Oracle BMCS US, O=Oracle Corporation, L=Redwood City, ST=California, C=US"))
    )

    In the preceding example, graphdb_low is the connect identifier.

  4. Update the JDBC URL in /etc/oracle/graph/pgx.conf file with the connect identifier determined in the preceding step along with the directory path to the unzipped wallet file. For example:
    ...
    "pgx_realm": {
      "implementation": "oracle.pg.identity.DatabaseRealm",
      "options": {
        "jdbc_url": "jdbc:oracle:thin:@graphdb_low?TNS_ADMIN=/etc/oracle/graph/wallets/<dbname>",
        "token_expiration_seconds": 3600,
    ...
    
  5. Finally, restart the graph server as shown:
    sudo systemctl restart pgx

14.2.4.3 Store the Database Password in a Keystore

PGX requires a database account to read data from the database into memory. The account should be a low-privilege account (see Security Best Practices with Graph Data).

As described in Reading Graphs from Oracle Database into the Graph Server (PGX), you can read data from the database into the graph server without specifying additional authentication as long as the token is valid for that database user. But if you want to access a graph from a different user, you can do so, as long as that user's password is stored in a Java Keystore file for protection.

You can use the keytool command that is bundled together with the JDK to generate such a keystore file on the command line. See the following script as an example:

# Add a password for the 'database1' connection
keytool -importpass -alias database1 -keystore keystore.p12
# 1. Enter the password for the keystore
# 2. Enter the password for the database
 
# Add another password (for the 'database2' connection)
keytool -importpass -alias database2 -keystore keystore.p12
 
# List what's in the keystore using the keytool
keytool -list -keystore keystore.p12

If you are using Java version 8 or lower, you should pass the additional parameter -storetype pkcs12 to the keytool commands in the preceding example.

You can store more than one password into a single keystore file. Each password can be referenced using the alias name provided.

Write the PGX graph configuration file to load a graph directly from relational tables

The following example loads a subset of the HR sample data from relational tables directly into PGX as a graph. The configuration file specifies a mapping from relational to graph format by using the concept of vertex and edge providers.

Note:

Specifying the vertex_providers and edge_providers properties loads the data into an optimized representation of the graph.

{
    "name":"hr",
    "jdbc_url":"jdbc:oracle:thin:@myhost:1521/orcl",
    "username":"hr",
    "keystore_alias":"database1",
    "vertex_id_strategy": "no_ids",
    "vertex_providers":[
        {
            "name":"Employees",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"FIRST_NAME",
                    "type":"string"
                },
                {
                    "name":"LAST_NAME",
                    "type":"string"
                },
                {
                    "name":"EMAIL",
                    "type":"string"
                },
                {
                    "name":"SALARY",
                    "type":"long"
                }
            ]
        },
        {
            "name":"Jobs",
            "format":"rdbms",
            "database_table_name":"JOBS",
            "key_column":"JOB_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"JOB_TITLE",
                    "type":"string"
                }
            ]
        },
        {
            "name":"Departments",
            "format":"rdbms",
            "database_table_name":"DEPARTMENTS",
            "key_column":"DEPARTMENT_ID",
            "key_type": "string",
            "props":[
                {
                    "name":"DEPARTMENT_NAME",
                    "type":"string"
                }
            ]
        }
    ],
    "edge_providers":[
        {
            "name":"WorksFor",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"EMPLOYEE_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Employees"
        },
        {
            "name":"WorksAs",
            "format":"rdbms",
            "database_table_name":"EMPLOYEES",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"JOB_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Jobs"
        },
        {
            "name":"WorkedAt",
            "format":"rdbms",
            "database_table_name":"JOB_HISTORY",
            "key_column":"EMPLOYEE_ID",
            "source_column":"EMPLOYEE_ID",
            "destination_column":"DEPARTMENT_ID",
            "source_vertex_provider":"Employees",
            "destination_vertex_provider":"Departments",
            "props":[
                {
                    "name":"START_DATE",
                    "type":"local_date"
                },
                {
                    "name":"END_DATE",
                    "type":"local_date"
                }
            ]
        }
    ]
}

Read the data

Now you can instruct PGX to connect to the database and read the data by passing in both the keystore and the configuration file to PGX, using one of the following approaches:

  • Interactively in the graph shell

    If you are using the graph shell, start it with the --secret_store option. It will prompt you for the keystore password and then attach the keystore to your current session. For example:

    cd /opt/oracle/graph
    ./bin/opg4j --secret_store /etc/my-secrets/keystore.p12
     
     enter password for keystore /etc/my-secrets/keystore.p12:
    

    Inside the shell, you can then use normal PGX APIs to read the graph into memory by passing the JSON file you just wrote into the readGraphWithProperties API:

    opg4j> var graph = session.readGraphWithProperties("config.json")
    graph ==> PgxGraph[name=hr,N=215,E=415,created=1576882388130]
    
  • As a PGX preloaded graph
    As a server administrator, you can instruct PGX to load graphs into memory upon server startup. To do so, modify the PGX configuration file at /etc/oracle/graph/pgx.conf and add the path the graph configuration file to the preload_graphs section. For example:
    {
      ...
      "preload_graphs": [{
        "name": "hr", 
        "path": "/path/to/config.json"
      }],
      "authorization": [{
        "pgx_role": "GRAPH_DEVELOPER",
        "pgx_permissions": [{
          "preloaded_graph": "hr",
          "grant": "read"
        }]
      },	
    	....
      ]
    }
    As root user, edit the service file at /etc/systemd/system/pgx.service and change the ExecStart command to specify the location of the keystore containing the password:
    
    ExecStart=/bin/bash start-server --secret-store /etc/keystore.p12

    Note:

    Please note that /etc/keystore.p12 must not be password protected for this to work. Instead protect the file via file system permission that is only readable by oraclegraph user.
    After the file is edited, reload the changes using:
    sudo systemctl daemon-reload
    Finally start the server:
    sudo systemctl start pgx
  • In a Java application

    To register a keystore in a Java application, use the registerKeystore() API on the PgxSession object. For example:

    import oracle.pgx.api.*;
     
    class Main {
       
      public static void main(String[] args) throws Exception {
        String baseUrl = args[0];
        String keystorePath = "/etc/my-secrets/keystore.p12";
        char[] keystorePassword = args[1].toCharArray();
        String graphConfigPath = args[2];
        ServerInstance instance = Pgx.getInstance(baseUrl);
        try (PgxSession session = instance.createSession("my-session")) {
          session.registerKeystore(keystorePath, keystorePassword);
          PgxGraph graph = session.readGraphWithProperties(graphConfigPath);
          System.out.println("N = " + graph.getNumVertices() + " E = " + graph.getNumEdges());
        }
      }
    }
    
    You can compile and run the preceding sample program using the Oracle Graph Client package. For example:
    cd $GRAPH_CLIENT
    // create Main.java with above contents
    javac -cp 'lib/*' Main.java
    java -cp '.:conf:lib/*' Main http://myhost:7007 MyKeystorePassword path/to/config.json
    

Secure coding tips for graph client applications

When writing graph client applications, make sure to never store any passwords or other secrets in clear text in any files or in any of your code.

Do not accept passwords or other secrets through command line arguments either. Instead, use Console.html#readPassword() from the JDK.

14.2.4.4 Adding Permissions to Publish the Graph

There are two ways by which you can view any graph in your graph server (PGX) session in the graph visualization application.

When you log into the graph visualization tool in your browser, that will be a different session from your JShell session or application session. To visualize the graph you are working on in your JShell session or application session in your graph visualization session, you can perform one of the following two steps:

  1. Get the session id of your working session using the PgxSession API, and use that session id when you log into the graph visualization application. This is the recommended option.
    opg4j> session.getId();
    $2 ==> "898bdbc3-af80-49b7-9a5e-10ace6c9071c"  //session id
    

    or

  2. Grant PGX_SESSION_ADD_PUBLISHED_GRAPH permission and then publish the graph as shown:
    1. Grant PGX_SESSION_ADD_PUBLISHED_GRAPH role in the database to the user visualizing the graph as shown in the following statement:
      GRANT PGX_SESSION_ADD_PUBLISHED_GRAPH TO <graphuser>
    2. Publish the graph when you are ready to visualize the graph using the publish API.

    Note:

14.2.4.5 Token Expiration

By default, tokens are valid for 1 hour.

Internally, the graph client automatically renews tokens which are about to expire in less than 30 minutes. This is also configurable by re-authenticating your credentials with the database. By default, tokens can only be automatically renewed for up to 24 times, then you need to login again.

If the maximum amount of auto-renewals is reached, you can log in again without losing any of your session data by using the GraphServer#reauthenticate (instance, "<user>", "<password>") API.

Note:

If a session time out occurs before you re-authenticate, then you may lose your session data.

For example:


opg4j> var graph = session.readGraphByName("BANK_GRAPH_VIEW",GraphSource.PG_PGQL)  // fails because token cannot be renewed anymore
opg4j> GraphServer.reauthenticate(instance, "<user>", "<password>".toCharArray()) // log in again
opg4j> var graph = session.readGraphByName("BANK_GRAPH_VIEW",GraphSource.PG_PGQL) // works now 
 

14.2.4.6 Customizing Roles and Permissions

You can fully customize the permissions to roles mapping by adding and removing roles and specifying permissions for a role. You can also authorize individual users instead of roles.

This topic includes examples of how to customize the permission mapping.

14.2.4.6.1 Checking Graph Permissions Using API

You can view your roles and graph permissions using the following PGX API methods:

Table 14-5 API for Checking Graph Permissions

Class Method Description
ServerInstance getPgxUsername() Name of the current user
ServerInstance getPgxUserRoles() Role names of the current user
ServerInstance getPgxGenericPermissions() Non-graph (system) permissions of the current user:
  • Pgx system permissions
  • File-location permissions
PgxGraph getPermission() Permission on the graph instance for a current user

You can get all permission-related information using the API in JShell as shown:

/bin/opg4j -b "https://<host>:<port>" -u "<graphuser>"
opg4j> instance
instance ==> ServerInstance[embedded=false,baseUrl=https://<host>:<port>,serverVersion=null]
opg4j> instance.getPgxUsername()
$2 ==> "ORACLE"
opg4j> instance.getPgxUserRoles()
$3 ==> [GRAPH_DEVELOPER]
opg4j> instance.getPgxGenericPermissions()
$4 ==> [PGX_SESSION_CREATE, PGX_SESSION_READ_MODEL, PGX_SESSION_ADD_PUBLISHED_GRAPH, PGX_SESSION_NEW_GRAPH, PGX_SESSION_GET_PUBLISHED_GRAPH, PGX_SESSION_MODIFY_MODEL]
opg4j> var g = session.readGraphByName("BANK_GRAPH_VIEW", GraphSource.PG_PGQL)
g ==> PgxGraph[name=BANK_GRAPH_VIEW,N=999,E=4993,created=1688558374973]
opg4j> g.getPermission() // To get graph permissions
$9 ==> MANAGE
import oracle.pg.rdbms.*;
import java.sql.Connection;
import java.sql.Statement;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlStatement;
import oracle.pgx.api.*;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import oracle.ucp.jdbc.PoolDataSource;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * This example shows how to get all permissions.
 */
public class GetPermissions
{

  public static void main(String[] args) throws Exception
  {
    int idx=0;
    String host               = args[idx++]; 
    String port               = args[idx++]; 
    String sid                = args[idx++]; 
    String user               = args[idx++]; 
    String password           = args[idx++];
    String graph              = args[idx++];
        
    Connection conn = null;
    PgxPreparedStatement stmt = null;
  
    try {
      
      // Get a jdbc connection
      PoolDataSource  pds = PoolDataSourceFactory.getPoolDataSource();
      pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
      pds.setURL("jdbc:oracle:thin:@"+host+":"+port +"/"+sid);
      pds.setUser(user);
      pds.setPassword(password);     
      conn = pds.getConnection();
      conn.setAutoCommit(false);
      
      ServerInstance instance = GraphServer.getInstance("http://localhost:7007", user, password.toCharArray());
      PgxSession session = instance.createSession("my-session");

      var statement = Files.readString(Path.of("/media/sf_Linux/Java/create-pg.pgql"));
      stmt = session.preparePgql(statement);
      stmt.execute();

      PgxGraph g = session.getGraph(graph);
      System.out.println("Graph: "+ g);
      
      String userName = instance.getPgxUsername();
      var userRoles = instance.getPgxUserRoles();
      var genericPermissions = instance.getPgxGenericPermissions();
      String graphPermission = g.getPermission().toString();

      System.out.println("Username is " + userName);
      System.out.println("User Roles are " + userRoles);
      System.out.println("Generic permissions are " + genericPermissions);
      System.out.println("Graph permission is " + graphPermission);

    }

    finally {
      // close the sql statment
      if (stmt != null) {
        stmt.close();
      }
      // close the connection
      if (conn != null) {
        conn.close();
      }
    }
  }
}

On execution, the code gives the following output:

Graph: PgxGraph[name=BANK_GRAPH_PG,N=1000,E=5001,created=1625731370402]
Username is ORACLE
User Roles are [GRAPH_DEVELOPER]
Generic permissions are [PGX_SESSION_MODIFY_MODEL, PGX_SESSION_CREATE, PGX_SESSION_NEW_GRAPH, PGX_SESSION_READ_MODEL, PGX_SESSION_ADD_PUBLISHED_GRAPH, PGX_SESSION_GET_PUBLISHED_GRAPH]
Graph permission is MANAGE

14.2.4.6.2 Adding and Removing Roles

You can add new role permission mappings or remove existing mappings by modifying the authorization list.

For example:


CREATE ROLE MY_CUSTOM_ROLE_1
GRANT PGX_SESSION_CREATE TO MY_CUSTOM_ROLE1 
GRANT PGX_SERVER_GET_INFO TO MY_CUSTOM_ROLE1 
GRANT MY_CUSTOM_ROLE1 TO SCOTT

14.2.4.6.3 Defining Permissions for Individual Users

In addition to defining permissions for roles, you can define permissions for individual users.

For example:

GRANT PGX_SESSION_CREATE TO SCOTT 
GRANT PGX_SERVER_GET_INFO TO SCOTT 

14.2.4.6.4 Defining Permissions to Use Custom Graph Algorithms

You can define permissions to allow developers to compile custom graph algorithms.

For example,
  1. Add the following static permission to the list of permissions:
    GRANT PGX_SESSION_COMPILE_ALGORITHM TO GRAPH_DEVELOPER

14.2.4.7 Revoking Access to the Graph Server

To revoke a user's ability to access the graph server, either drop the user from the database or revoke the corresponding roles from the user, depending on how you defined the access rules in your pgx.conf file.

For example:

REVOKE graph_developer FROM scott

Revoking Graph Permissions

If you have the MANAGE permission on a graph, you can revoke graph access from users or roles using the PgxGraph#revokePermission API. For example:

PgxGraph g = ...
g.revokePermission(new PgxRole("GRAPH_DEVELOPER")) // revokes previously granted role access
g.revokePermission(new PgxUser("SCOTT")) // revokes previously granted user access

14.2.4.8 Examples of Custom Authorization Rules

You can define custom authorization rules for developers.

Example 14-1 Allowing Developers to Publish Graphs

Sharing of graphs with other users should be done in Oracle Database where possible. Use GRANT statements on the database tables so that other users can create graphs from the tables.

In the graph server (PGX) you can use the following permissions to share a graph that is already in memory, with other users connected to the graph server.

Table 14-6 Allowed Permissions

Permission Actions Enabled by this Permission
READ
  • READ the graph via the PGX API or in PGQL queries in PGX, create a subgraph, or clone the graph
MANAGE
  • Publish the graph or snapshot
  • Includes READ and EXPORT
  • Grant or revoke READ and EXPORT permissions on the graph
EXPORT
  • Export the graph to a file.
  • Includes READ permission.

The creator of the graph automatically gets the MANAGE permission granted on the graph. If you have the MANAGE permission, you can grant other roles or users READ or EXPORT permission on the graph. You cannot grant MANAGE on a graph. The following describes an example of granting READ permission on a graph to the GRAPH_DEVELOPER role by userA:

import oracle.pgx.api.*;
import oracle.pgx.common.auth.*;
...
PgxSession session = GraphServer.getInstance("<base-url>", "<userA>", "<password-of-userA").createSession("userA");
PgxGraph g = session.readGraphByName("SAMPLE_GRAPH", GraphSource.PG_PGQL);
g.grantPermission(new PgxRole("GRAPH_DEVELOPER"), PgxResourcePermission.READ);
g.publish();
Now other users with the GRAPH_DEVELOPER role can access this graph and have READ access on it, as shown in the following example of userB:
PgxSession session = GraphServer.getInstance("<base-url>", "<userB>", "<password-of-userB").createSession("userB")
PgxGraph g = session.getGraph("sample_graph")
g.queryPgql("select count(*) from match (v)").print().close()

Similarly, graphs can be shared with individual users instead of roles, as shown in the following example:

g.grantPermission(new PgxUser("OTHER_USER"), PgxResourcePermission.EXPORT)

where OTHER_USER is the user name of the user that will receive the EXPORT permission on graph g.

Example 14-2 Allowing Developers to Access Preloaded Graphs

To allow developers to access preloaded graphs (graphs loaded during graph server startup), grant the read permission on the preloaded graph in the pgx.conf file. For example:

"preload_graphs": [{
  "path": "/data/my-graph.json",
  "name": "global_graph"
}],
"authorization": [{
  "pgx_role": "GRAPH_DEVELOPER",
  "pgx_permissions": [{
    "preloaded_graph": "global_graph"
    "grant": "read"
  },
...

You can grant READ, EXPORT, or MANAGE permission.

Example 14-3 Allowing Developers Access to the Local File System

To allow developers access to the local file system (where the graph server runs), you must first declare a directory and then map it to a read or write permission. For example:

CREATE OR REPLACE DIRECTORY pgx_file_location AS '/opt/oracle/graph/data'
GRANT READ ON DIRECTORY pgx_file_location TO GRAPH_DEVELOPER

Similarly, you can add another permission with GRANT WRITE to allow write access. Such a write access is required in order to export graphs.

Note that in addition to the preceding configuration, the operating system user that runs the graph server process must have the corresponding directory privileges to actually read or write into those directories.

Example 14-4 Allowing Access to Directories on Autonomous Database

To allow developers to read and write from files in Oracle Autonomous Database, you must perform the following steps:

  1. Connect to your Autonomous Database instance as an ADMIN user using any of the SQL based Oracle Database tools or using Database Actions, the built-in web-based interface.
  2. Create the directory by specifying the path to the directory using the graph: prefix as shown:
    CREATE OR REPLACE DIRECTORY pgx_file_location AS 'graph:/opt/oracle/graph/data'
  3. Grant read or write permissions to the directory for the desired role. For example:
    GRANT READ ON DIRECTORY pgx_file_location TO GRAPH_DEVELOPER

14.2.4.9 Kerberos Enabled Authentication for the Graph Server (PGX)

The graph server (PGX) can authenticate users using an Oracle Database with Kerberos enabled as identity provider.

You can log into the graph server using a Kerberos ticket and the actions which you are allowed to do on the graph server are determined by the roles that have been granted to you in the Oracle Database.

14.2.4.9.1 Prerequisite Requirements

In order to enable Kerberos authentication on the graph server (PGX), the following system requirements must be met:

  • The database needs to have Kerberos authentication enabled. See Configuring Kerberos Authentication for more information.
  • Both the database and the Kerberos Authentication Server need to be reachable from the host where the graph server runs.
  • The database is prepared for graph server authentication. That is, relevant graph roles have been granted to users who will log into the graph server.

14.2.4.9.2 Prepare the Graph Server for Kerberos Authentication

The following are the steps to enable Kerberos authentication on the graph server (PGX):
  1. Locate the pgx.conf file of your installation.

    Note:

    If you installed the graph server via RPM, the file is located at: /etc/oracle/graph/pgx.conf
  2. Locate the krb5_conf_file line of the realm options, inside the pgx.conf file:
    "pgx_realm": {
      "implementation": "oracle.pg.identity.DatabaseRealm",
      "options": {
        ...
        "krb5_conf_file": "<REPLACE-WITH-KRB5-CONF-FILE-PATH-TO-ENABLE-KERBEROS-AUTHENTICATION>",
        "krb5_ticket_cache_dir": "/dev/shm",
        "krb5_max_cache_size": 1024
      }
    },
  3. Replace the text with the krb5.conf file that you are using for the database and user authentication. For example:
    "pgx_realm": {
      "implementation": "oracle.pg.identity.DatabaseRealm",
      "options": {
        ...
        "krb5_conf_file": "/etc/krb5.conf",
        "krb5_ticket_cache_dir": "/dev/shm",
        "krb5_max_cache_size": 1024
      }
    },

    Note:

    The file provided for the krb5_conf_file option needs to be valid and readable by the graph server. In case you don't replace the krb5_conf_file value or the value is empty, then the graph server will not use Kerberos authentication.

    Also, you can set the cache directory that will be used for the graph server to temporarily store Kerberos tickets given by clients as well as the maximum cache size after which new login attempts will be rejected. The cache size represents the maximum amount of concurrent Kerberos sessions active on the graph server.

14.2.4.9.3 Login to the Graph Server Using Kerberos Ticket

The following are the steps to login to the graph server (PGX) using Kerberos ticket:
  1. Create a new Kerberos ticket using the okinit command:
    $ okinit <username>

    This will prompt for your password and then create a new Kerberos ticket.

  2. Connect to a remote graph server with only the base URL parameter using JShell:
    $ opg4j -b https://localhost:7007
    Or using Python client:
    $ opg4py -b https://localhost:7007
    On Linux, JShell and Python interactive client shells automatically detect the Kerberos ticket on your local file system and use that to authenticate with the graph server.
  3. In case the auto-detection is not working, you can also explicitly pass in the ticket to the shell. Run the oklist command, to find the location of the ticket on the local file system.
    $ oklist
     
    Kerberos Utilities for Linux: Version 19.0.0.0.0 - Production on 31-MAR-2021 15:26:46
     
    Copyright (c) 1996, 2019 Oracle.  All rights reserved.
     
    Configuration file : /etc/krb5.conf.
    Ticket cache: FILE:/tmp/krb5cc_54321
    Default principal: oracle@realm
  4. Specify your Kerberos ticket path using the --kerberos_ticket parameter. For example, using JShell:
    $ opg4j -b https://localhost:7007 --kerberos_ticket /tmp/krb5cc_54321
    Or using Python Client:
    $ opg4py -b https://localhost:7007 --kerberos_ticket /tmp/krb5cc_54321

    If you are using a Java client program (or JShell on embedded mode), you can get a server instance using the following API:

    ...
    ServerInstance instance = GraphServer.getInstance("https://localhost:7007", "/tmp/krb5cc_54321");
    PgxSession session = instance.createSession("my-session");
    ...

    If you are using a Python Client program (or opg4py on embedded mode), you can get a server instance using the following API

    ...
    instance = graph_server.get_instance("https://localhost:7007", "/tmp/krb5cc_54321")
    session = instance.create_session("my-session")
    ...
    If you are connecting to a remote graph server, all you need is the Oracle Graph Client to be installed. For example:
    import sys
    import pypgx as pgx
     
    sys.path.append("/path/to/graph/client/oracle-graph-client-21.2.0/python/pypgx/pg/rdbms")
     
    import graph_server
      
    base_url = "https://localhost:7007"
    kerberos_ticket = "/tmp/krb5cc_54321"
      
    instance = graph_server.get_instance(base_url, kerberos_ticket)
    print(instance)