16.2.4 User Authentication and Authorization
The Oracle Graph server (PGX) uses an Oracle Database as identity manager. You can log into the graph server (PGX) using your database credentials (user name and password).
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 Oracle Database.
- Basic Steps for Using a Database for Authentication
You can follow the steps explained in this section to authenticate users to the graph server (PGX). - Prepare the Graph Server for Database Authentication
Locate thepgx.conffile of your installation. - Store the Database Password in a Keystore
- 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. - Token Expiration
By default, tokens are valid for 1 hour. - 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. - 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. - Examples of Custom Authorization Rules
You can define custom authorization rules for developers.
Parent topic: Oracle Graph Server Installation
16.2.4.1 Basic Steps for Using a Database for Authentication
You can follow the steps explained in this section to authenticate users to the graph server (PGX).
- Privileges and Roles in the Database
This section describes the database roles and privileges that are required only if you are using the graph server (PGX).
Parent topic: User Authentication and Authorization
16.2.4.1.1 Privileges and Roles in the Database
This section describes the database roles and privileges that are required only if you are using the graph server (PGX).
Table 16-4 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.
Parent topic: Basic Steps for Using a Database for Authentication
16.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
vim graph-server-webapp-<version>.warInside 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 pgxPreparing the Graph Server (PGX) to Connect to Autonomous AI Database
You can configure your graph server(PGX) to connect to an Autonomous AI 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 AI Database
instance and update the JDBC URL in /etc/oracle/graph/pgx.conf file.
- Download and save the wallet for your Autonomous AI Database instance from the Oracle Cloud Infrastructure (OCI) Console. See Download Client Credentials (Wallets) for more information.
- 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> - Determine the connect identifier from the
tnsnames.orafile 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_lowis the connect identifier. - Update the JDBC URL in
/etc/oracle/graph/pgx.conffile 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, ... - Finally, restart the graph server as
shown:
sudo systemctl restart pgx
Parent topic: User Authentication and Authorization
16.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 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
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
- Read the data
- Secure coding tips for graph client applications
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_storeoption. 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
readGraphWithPropertiesAPI:opg4j> var graph = session.readGraphWithProperties("config.json") graph ==> PgxGraph[name=hr,N=215,E=415,created=1576882388130] - As a PGX preloaded graphAs 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.confand add the path the graph configuration file to thepreload_graphssection. 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.serviceand change theExecStartcommand to specify the location of the keystore containing the password:ExecStart=/bin/bash start-server --secret-store /etc/keystore.p12Note:
Please note that/etc/keystore.p12must not be password protected for this to work. Instead protect the file via file system permission that is only readable byoraclegraphuser.After the file is edited, reload the changes using:sudo systemctl daemon-reloadFinally start the server:sudo systemctl start pgx - In a Java application
To register a keystore in a Java application, use the
registerKeystore()API on thePgxSessionobject. 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.
Parent topic: User Authentication and Authorization
16.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:
Parent topic: User Authentication and Authorization
16.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.
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
Parent topic: User Authentication and Authorization
16.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.
- Checking Graph Permissions Using API
- Adding and Removing Roles
You can add new role permission mappings or remove existing mappings by modifying the authorization list. - Defining Permissions for Individual Users
In addition to defining permissions for roles, you can define permissions for individual users. - Defining Permissions to Use Custom Graph Algorithms
You can define permissions to allow developers to compile custom graph algorithms.
Parent topic: User Authentication and Authorization
16.2.4.6.1 Checking Graph Permissions Using API
You can view your roles and graph permissions using the following PGX API methods:
Table 16-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:
|
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
Parent topic: Customizing Roles and Permissions
16.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 SCOTTParent topic: Customizing Roles and Permissions
16.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
Parent topic: Customizing Roles and Permissions
16.2.4.6.4 Defining Permissions to Use Custom Graph Algorithms
You can define permissions to allow developers to compile custom graph algorithms.
Parent topic: Customizing Roles and Permissions
16.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 scottRevoking 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
Parent topic: User Authentication and Authorization
16.2.4.8 Examples of Custom Authorization Rules
You can define custom authorization rules for developers.
Example 16-1 Allowing Developers to Publish Graphs
You can share graphs with other users using 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 16-6 Allowed Permissions
| Permission | Actions Enabled by this Permission |
|---|---|
READ |
|
MANAGE |
|
EXPORT |
|
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();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 16-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 16-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_DEVELOPERSimilarly, 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 16-4 Allowing Access to Directories on Autonomous AI Database
To allow developers to read and write from files in Oracle Autonomous AI Database, you must perform the following steps:
- Connect to your Autonomous AI Database instance as an ADMIN user using any of the SQL based database tools or using Database Actions, the built-in web-based interface.
- 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' - Grant read or write permissions to the directory for the desired role. For
example:
GRANT READ ON DIRECTORY pgx_file_location TO GRAPH_DEVELOPER
Parent topic: User Authentication and Authorization