How To Generate & Use OCI Pre-Authenticated Requests from APEX

How To Generate & Use OCI Pre-Authenticated Requests from APEX

ยท

6 min read

Introduction

Sometimes you need to give a user or another system temporary access to get or upload files from/to Oracle Cloud Infrastructure (OCI) Object Storage. This temporary access is achieved using Pre-Authenticated Requests. Pre-Authenticated Requests (PARs) are pre-signed URLs that provide temporary access to read or write files from/to a specified bucket or a specified path within a bucket. This post will show you how to generate and consume PARs from within your APEX Applications.

Pre-Authenticated Requests should be used with caution. A PAR URL gives anyone with the URL access to the Object Store resources identified in the request.

You can create a pre-authenticated request that grants read, write, or read/write access to one of the following:

  • All objects in a bucket
  • A specific object in a bucket
  • All objects in a bucket that have a specified prefix

For PARs that apply to multiple objects, you can also decide whether you want to let users list those objects.

Example Use Cases

  • Where systems cannot authenticate into OCI using OCI Credentials
  • Provide partners temporary access to upload files to a folder within a bucket
  • Provide temporary access to customers to download new versions of Software

Sample Code

I created a PL/SQL package and function which allows you to generate OCI Pre-Authenticated requests from APEX. You can download it from my Github repository.

OCI Configurations

This section will describe the Oracle Cloud Infrastructure (OCI) setups required for this solution.

Dependencies

Please refer to my previous post Secure APEX Access to OCI Object Storage. This post will show you how to perform the following configurations in the OCI Console. I will reference the configuration names in quotes throughout this blog post:

  • Creating an Object Store Compartment 'APEX_OCI_BLOG'
  • Creating an Object Store Bucket 'APEX_OCI_BLOG_FILES'
  • Creating a Service Account 'APEX_OCI_BLOG_Service_Account'
  • Create a Security Group 'APEX_OCI_BLOG_Security_Group'

Additional OCI Configurations

Once you have completed the steps from the previous section, create the following additional Policy in the same OCI Compartment. PAR_Create_Policy_Screenshot.png

The first policy statement: Allow group APEX_OCI_BLOG_Security_Group manage buckets in compartment APEX_OCI_BLOG where all {target.bucket.name='APEX_OCI_BLOG_FILES', any {request.permission='PAR_MANAGE'}}, allows users that belong to the APEX_OCI_BLOG_Security_Group to create PARs in the APEX_OCI_BLOG_FILES bucket.

The second policy statement: Allow group APEX_OCI_BLOG_Security_Group to manage objects in compartment APEX_OCI_BLOG where all {target.bucket.name='APEX_OCI_BLOG_FILES', any {request.permission='OBJECT_CREATE', request.permission='OBJECT_READ',request.permission='OBJECT_OVERWRITE'}}, allows users that belong to the APEX_OCI_BLOG_Security_Group to create, update and read objects in the APEX_OCI_BLOG_FILES bucket.

As the documentation mentions, not only must the user have access to create PARs, but they must also have permission to perform the actions passed on in the PAR (i.e., OBJECT_CREATE, OBJECT_READ, etc.). You can adjust the permissions in the second policy statement to suit your use case.

APEX Code and Configurations

This section will examine the PL/SQL code and APEX configurations needed to support this solution.

APEX Web Credential

Please refer to my previous post Secure APEX Access to OCI Object Storage. This post describes creating a Web Credential in APEX for your OCI Service Account. For this post, the Web Credential static ID is APEX_OCI_BLOG_CREDENTIAL.

PL/SQL Function to Generate a PAR

In the package cndemo_oci_pre_auth_requests_pk you will see a function called generate_pre_auth_request. This function can be called from APEX to generate a PAR URL. You can see example calls to this function later in this post.

PL/SQL Block to Generate a PAR

The PL/SQL block below borrows the logic from the function generate_pre_auth_request and makes it available in a PL/SQL block. The in-line comments describe what the code is doing.

OCI REST Service Documentation Links

Using a PAR

Now that we can generate PARs, how do we use these secured URLs to get and upload files from/to OCI Object Store? This section describes two examples, one to write files to a folder in a bucket and another to get a specific file from a particular folder.

Example to Create/Upload Files

In this example, we generate a PAR to allow customers to upload files to Object Store using a secured URL.

  • Target Bucket Name: APEX_OCI_BLOG_FILES
  • Target Folder in Bucket Root: PAR_TEST_FOLDER

Code to generate PAR for this example:

DECLARE
  l_par_url   VARCHAR2(1000);
BEGIN
  l_par_url := cndemo_oci_pre_auth_requests_pk.generate_pre_auth_request
    -- PAR will expire in 1 Hour
   (p_expiration_unit   => 'HOUR',
    p_expiration_value  => 1,
    -- PAR allows the holder of the URL to create any file
    p_access_type       => 'AnyObjectWrite',
    -- PAR restricts the holder of the URL to create files in the PAR_TEST_FOLDER folder
    p_object_name       => 'PAR_TEST_FOLDER',
    -- PAR allows the holder to list files in the folder PAR_TEST_FOLDER.
    p_object_listing    => 'ListObjects');
  dbms_output.put_line ('URL: '||l_par_url);
END;

-- Parameters:
-- p_expiration_unit   Values: [DAY,HOUR,MINUTE,SECOND]
-- p_expiration_value  Number of p_expiration_unit used to calculate URL expiration time.
-- p_access_type       Permissions: [ObjectRead, ObjectWrite, ObjectReadWrite, AnyObjectWrite, AnyObjectRead, AnyObjectReadWrite]
-- p_object_name       Object name or Prefix of objects in the bucket that URL has access to.
-- p_object_listing    Allow URL to list-objects. Values: [Deny,ListObjects]

PAR Generated by the above code: https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/

In our example, we need to append the folder name (p_object_name) and the name we want the file to be called when uploaded to the folder. The completed URL looks like this: https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Dark.png

The screenshot below shows how you can upload a file using the above PAR in Postman: Postman_PUT_File_Using_PAR_Example.png

Here is the curl generated by Postman:

curl --location --request PUT 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/QzYvrxQ2m3fwUbRELr2auXYIyDYkWxsMeNj1f3JjSKkXU_9P8XrR4RymKQfG3FYn/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Dark.png' \
--header 'Content-Type: image/png' \
--data-binary '@/Users/jdixon/Documents/Technical/My Blogs/Graphics/APEX Logos/APEX_Logo_Dark.png'

Here is a screenshot of the file that was uploaded to OCI Object Store: Object_Store_SHowing_Uploaded_File.png

Example to Get a File

In this example, we are generating a PAR to allow customers to download a specific file from a particular folder in Object Store.

  • Target Bucket Name: APEX_OCI_BLOG_FILES
  • Target Folder and File: PAR_TEST_FOLDER/APEX_Logo_Light.png

Here is a screenshot of the file we want holders of the PAR to access: Object_Store_Showing_File_Get.png

Code to generate PAR for this example:

DECLARE
  l_par_url   VARCHAR2(1000);
BEGIN
  l_par_url := cndemo_oci_pre_auth_requests_pk.generate_pre_auth_request
    -- PAR will expire in 1 Hour
   (p_expiration_unit   => 'HOUR',
    p_expiration_value  => 1,
    -- PAR allows the holder of the URL to get a file
    p_access_type       => 'ObjectRead',
    -- PAR is restricted to the APEX_Logo_Light.png file 
    --  in the PAR_TEST_FOLDER folder.
    p_object_name       => 'PAR_TEST_FOLDER/APEX_Logo_Light.png',
    -- PAR does not allow the holder to list files.
    p_object_listing    => 'Deny');
  dbms_output.put_line ('URL: '||l_par_url);
END;

PAR Generated by the above code: https://objectstorage.us-ashburn-1.oraclecloud.com/p/q7CeVldJj7d5pabY16kTWsREfr8NgjTRMAbBpNpBmAIPT2KYCyvIJK4o77fKqbrx/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png

The screenshot below shows how to get the file using the above PAR in Postman: Postman_GET_File_Using_PAR_Example.png

Here is the curl generated by Postman:

curl --location --request GET 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/q7CeVldJj7d5pabY16kTWsREfr8NgjTRMAbBpNpBmAIPT2KYCyvIJK4o77fKqbrx/n/nueva/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png'

Using a PAR URL to get a file from PL/SQL is easy with apex_web_service.make_rest_request_b

DECLARE
  l_par_url       VARCHAR2(1000);
  l_response_blob BLOB;
BEGIN
  -- For a GET, use the complete URL returned from generating the PAR
  l_par_url := 'https://objectstorage.us-ashburn-1.oraclecloud.com/p/6gLghRVH8_NqRy2goZdhp-p0Ifr5JlR2YrkBObNjBJ2BmSS1s5hXysgzoFFV7WOX/n/test/b/APEX_OCI_BLOG_FILES/o/PAR_TEST_FOLDER/APEX_Logo_Light.png';
  -- No additional authentication or credentials are required
  l_response_blob := apex_web_service.make_rest_request_b
   (p_url         => l_par_url,
    p_http_method => 'GET');
  dbms_output.put_line ('File Size: '||dbms_lob.getlength(l_response_blob));
END;

Conclusion

In this post, I described how Pre-authenticated requests allow you to provide temporary secure access to read or write files from/to OCI Object Store. I also showed you how you can generate and consume Pre-authenticated requests directly from your APEX applications.

๐Ÿ”— Read More

ย