Configure Oracle's XDB Server for Web Applications

Oracle Community

Configure Oracle's XDB Server for Web Applications

There are many developers who use Oracle APEX to develop robust web applications because it’s simply a great tool. While APEX gets better with each new release, there are developers who want to know how to build native PL/SQL web applications.

Oracle APEX uses Oracle XML Database (XDB) Server as its engine. The XDB Server is a multiprotocol web server that lets you configure it with the DBMS_XDB and DBMS_EPG PL/SQL Built-in packages. You also have the ability to configure the XDB Server to concurrently run standalone native PL/SQL web applications.

This article shows you how to configure the XDB Server to run PL/SQL native web applications. It shows you two approaches. The first uses a standard schema, which requires a schema name and password at login. The second uses the anonymous schema, which lets you embed your Access Control List and authentication functions inside the database.

This article has two parts that involve setting up Data Access Descriptors (DADs). They are:

  • Setting Up a Secured DAD
  • Setting Up an Unsecured DAD

You should read through how to setup a secured DAD before you read about setting up an unsecured DAD. Robust native PL/SQL web applications require you to use an unsecured DAD approach. The approach is direct and limits the discussion of the many facets of XDB Database. You can read more about the XDB in the Oracle XML DB Developer’s Guide.

Setting Up a Secured DAD

A Secured DAD uses basic HTTP authentication, and discloses the schema name and password to all you log into the application. Basic HTTP authentication starts when you authenticate and ends when you close the browser.

You must setup a port for your native PL/SQL web application. Since the APEX application uses port 8080, you should use the same port. If you change the port number, it is also changes for the APEX application. You set the port number to the default with the SETHTTPPORT procedure of the DBMS_XDB package, like this:

SQL> DECLARE
  2    lv_port NUMBER;
  3  BEGIN
  4    SELECT dbms_xdb.gethttpport()
  5    INTO lv_port
  6    FROM dual;
  7
  8    /* Check for default port and reset. */
  9    IF NOT lv_port = 8080 THEN
 10      dbms_xdb.sethttpport(8080);
 11    END IF;
 12  END;
 13  /

After you setup the HTTP port number, you need to create and authorize the secured DAD. You use the CREATE_DAD procedure to create the DAD, and the AUTHORIZE_DAD procedure to authorize the DAD.

The following command creates the STUDENT_DAD DAD:

SQL> BEGIN
  2    dbms_epg.create_dad(
  3        dad_name => 'STUDENT_DAD'
  4      , path => '/studentdb/*');
  5  END;
  6  /

This command creates the DAD and points the DAD to a /studentdb/* URL component. The /studentdb/ component identifies a path element. The trailing asterisk identifies all executable PL/SQL procedures inside the DAD.

The following command authorizes the STUDENT_DAD DAD:

SQL> BEGIN
  2    dbms_epg.authorize_dad(
  3        dad_name => 'STUDENT_DAD'
  4      , user => 'STUDENT');
  5  END;
  6  /

The DAD name is the same but the path points to an Oracle STUDENT schema. Effectively, the CREATE_DAD procedure maps the DAD to the URL component; and the AUTHORIZE_DAD procedure maps the DAD to the user’s schema where you deploy the native PL/SQL procedures.

After you create and authorize the DAD, you can create a helloworld procedure to test your configuration. You should create it in the STUDENT user’s schema, which is a STUDENT container schema.

The following uses Oracle’s built-in PL/SQL web toolkit to create a native PL/SQL web page. Only line 11 is dynamic. The USER keyword on line 11 returns the owning schema name at runtime.

SQL> CREATE OR REPLACE PROCEDURE student.helloworld AS
  2  BEGIN
  3    -- Set an HTML meta tag and render page.
  4    owa_util.mime_header('text/html'); -- <META Content-type:text/html>
  5    htp.htmlopen; -- <HTML>
  6    htp.headopen; -- <HEAD>
  7    htp.htitle('Hello World!'); -- <TITLE>HelloWorld!</TITLE>
  8    htp.headclose; -- </HEAD>
  9    htp.bodyopen; -- <BODY>
 10    htp.line; -- <HR>
 11    htp.print('Hello ['||USER||']!'); -- Hello [dynamic user_name]!
 12    htp.line; -- <HR>
 13    htp.bodyclose; -- </BODY>
 14    htp.htmlclose; -- </HTML>
 15  END HelloWorld;
 16  /

After creating the helloworld function, you call it from a URL in a browser. The server hostname is oracle12c, which means you would call the native PL/SQL procedure with the following syntax:  

http://oracle12c/studentdb/helloworld

It prompts for Basic HTTP security credentials, like this:

 

You need to provide the STUDENT user name or a CDB Oracle 12c C##PLSQL user name, and the password to the dialog box. After entering the correct credentials, you should see the following web page if you're using the Oracle 12c C##PLSQL user name:

  

The helloworld procedure renders a web page with the title element of “Hello World!” The helloworld procedure renders a content body with the message of Hello [C##PLSQL]!

There’s only one downside when you use Oracle’s PL/SQL web toolkit. The PL/SQL web toolkit renders HTML tags in uppercase text, as you can see in the following source code:

<HTML>
<HEAD>
<TITLE>Hello World!</TITLE><H1>Hello World!</H1>
</HEAD>
<BODY>
<HR>
Hello [C##PLSQL]!
<HR>
</BODY>
</HTML>

You need to type them as string literals in the procedure if you want the browser to render them in lowercase HTML tags. Alternatively, you can write your own replacement to the HTF and HTP PL/SQL built-in packages to render lowercase HTML tags.

This section has shown you how to render a native PL/SQL web application with a secured DAD. The next section builds on this discussion and shows you how to build them with an unsecured DAD.

Setting Up a Unsecured DAD

The benefit of setting up a native PL/SQL web application with an unsecured DAD is that you can have much more control. You can setup your own encryption, authentication, and application metadata.

You need to determine the current configuration of the XDB server before you can configure it to meet your needs. Oracle Database 12c, like prior releases, provides the epgstat.sql script in the Oracle home. This script lets you check the XDB server’s current configuration.

The following query displays the configuration file for the XDB server:

SQL> SELECT dbms_xdb.cfg_get() FROM dual;

You can run the script as the SYSTEM user, like so:

SQL> ?/rdbms/admin/epgstat.sql

It should return the following initial configuration, which includes your secured STUDENT_DAD DAD setup:

+--------------------------------------+
| XDB protocol ports:                  |
| XDB is listening for the protocol    |
| when the protocol port is non-zero.  |
+--------------------------------------+

HTTP Port FTP Port
--------- --------
8080      0

1 row selected.

+---------------------------+
| DAD virtual-path mappings |
+---------------------------+

Virtual Path DAD Name
-------------------------------- --------------------------------
/apex/*                          APEX
/studentdb/*                     STUDENT_DAD

2 rows selected.

+----------------+
| DAD attributes |
+----------------+

DAD Name DAD Param DAD Value

------------ --------------------------- ----------------------------------------
APEX         database-username           ANONYMOUS
             default-page                apex
             document-table-name         wwv_flow_file_objects$
             request-validation-function wwv_flow_epg_include_modules.authorize
             document-procedure          wwv_flow_file_mgr.process_download
             nls-language                american_america.al32utf8
             document-path               docs

7 rows selected.

+---------------------------------------------------+
| DAD authorization: |
| To use static authentication of a user in a DAD, |
| the DAD must be authorized for the user. |
+---------------------------------------------------+

DAD Name                         User Name
-------------------------------- --------------------------------
STUDENT_DAD                      STUDENT

1 row selected.

+----------------------------+
| DAD authentication schemes |
+----------------------------

DAD Name User Name Auth Scheme
-------------------- -------------------------------- ------------------
APEX                 ANONYMOUS                        Anonymous
STUDENT_DAD                                           Dynamic

2 rows selected.

+--------------------------------------------------------+
| ANONYMOUS user status: |
| To use static or anonymous authentication in any DAD, |
| the ANONYMOUS account must be unlocked. |
+--------------------------------------------------------+

Database User   Status
--------------- --------------------
ANONYMOUS       EXPIRED & LOCKED

1 row selected.

+-------------------------------------------------------------------+
| ANONYMOUS access to XDB repository: |
| To allow public access to XDB repository without authentication, |
| ANONYMOUS access to the repository must be allowed. |
+-------------------------------------------------------------------+

Allow repository anonymous access?
----------------------------------
false

1 row selected.

All the key values from the diagnostic script are bold highlighted. There are two things that you need to change to the configuration. You need to unlock the ANONYMOUS schema and open access to the ANONYMOUS schema.

You need to unlock the ANONYMOUS schema, which you can do with the following syntax as the SYSTEM user:

SQL> ALTER USER anonymous ACCOUNT UNLOCK;
SQL> ALTER USER anonymous IDENTIFIED BY null;

Unlocking the access to the ANONYMOUS repository is a bit more complex and requires an anonymous PL/SQL block. The following opens the ANONYMOUS repository:

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2    lv_configxml XMLTYPE;
  3    lv_value VARCHAR2(5) := 'true'; -- (true/false)
  4  BEGIN
  5    lv_configxml := DBMS_XDB.cfg_get();
  6
  7    -- Check for the element.
  8    IF lv_configxml.existsNode('/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access') = 0 THEN
  9      -- Add missing element.
 10      SELECT insertChildXML
 11              ( lv_configxml
 12              ,'/xdbconfig/sysconfig/protocolconfig/httpconfig'
 13              ,'allow-repository-anonymous-access'
 14              , XMLType('<allow-repository-anonymous-access xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd">'
 15                || lv_value
 16                || '</allow-repository-anonymous-access>')
 17              ,'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"')
 18      INTO lv_configxml
 19      FROM dual;
 20
 21      dbms_output.put_line('Element inserted.');
 22    ELSE
 23      -- Update existing element.
 24      SELECT updateXML
 25              ( DBMS_XDB.cfg_get()
 26              ,'/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access/text()'
 27              , lv_value
 28              ,'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"')
 29      INTO lv_configxml
 30      FROM dual;
 31
 32      dbms_output.put_line('Element updated.');
 33    END IF;
 34
 35    -- Configure the element.
 36    dbms_xdb.cfg_update(lv_configxml);
 37    dbms_xdb.cfg_refresh;
 38  END;
 39  /

It should print the following when run successfully:

Element inserted.

You should see the following differences when you rerun the epgstat.sql script:

+--------------------------------------------------------+
| ANONYMOUS user status: |
| To use static or anonymous authentication in any DAD, |
| the ANONYMOUS account must be unlocked. |
+--------------------------------------------------------+

1 row selected.

Database User Status
--------------- --------------------
ANONYMOUS OPEN

+-------------------------------------------------------------------+
| ANONYMOUS access to XDB repository: |
| To allow public access to XDB repository without authentication, |
| ANONYMOUS access to the repository must be allowed. |
+-------------------------------------------------------------------+

Allow repository anonymous access?
----------------------------------
true

1 row selected.

After you have open the ANONYMOUS schema and allow access to the ANONYMOUS repository, you need to grant execute privilege from the STUDENT user to the ANONYMOUS user and create a synonym for the ANONYMOUS user. The ANONYMOUS user needs a synonym for the helloworld procedure owned by the STUDENT user.

You grant the privilege and create the synonym as the SYSTEM user with the following syntax:

SQL> GRANT EXECUTE ON student.helloworld2 TO anonymous;
SQL> CREATE SYNONYM anonymous.helloworld2 FOR student.helloworld2;

You need to create and authorize a new GENERIC_DAD DAD for the next example. You do that with the following command creates the GENERIC_DAD DAD:

SQL> BEGIN
  2    dbms_epg.create_dad(
  3        dad_name => 'GENERIC_DAD'
  4      , path => '/db/*');
  5  END;
  6  /

You should note the URL subdirectory for this approach is db. The next command authorizes the GENERIC_DAD DAD:


SQL> BEGIN
  2    dbms_epg.authorize_dad(
  3        dad_name => 'GENERIC_DAD'
  4      , user => 'ANONYMOUS');
  5  END;
  6  /

The anonymous configuration requires a new step. You set the GENERIC_DAD DAD's database-username as generic with the following call to the SET_DAD_ATTRIBUTE of the DBMS_EPG package:

SQL> BEGIN
  2    dbms_epg.set_dad_attribute(
  3        dad_name => 'GENERIC_DAD'
  4      , attr_name => 'database-username'
  5      , attr_value => 'ANONYMOUS');
  6  END;
  7  /

At this point, you should close the browser to end the scope of the Basic HTTP security permission from the secured DAD example. Launch the browser and enter the following URL:

http://oracle12c/db/helloworld

You should note that the virtual directory in the URL has changed from studentdb to db. The studentdb virtual directory maps to the secured DAD. The db virtual directory maps to the unsecured DAD.

The native PL/SQL web page should render the following native PL/SQL web page:

  

You should notice that the user is the ANONYMOUS user while the actual stored procedure is the helloworld procedure stored in the C##PLSQL container database user’s schema.

The connection through the ANONYMOUS schema doesn’t require credentials. You should only deploy synonyms to stored procedures that you deploy in other schemas. The stored procedures should verify access against your internal authentication functions and procedures.  You can read how to create a PL/SQL authentication function in this other ToadWorld post.

This article has shown you how to write, deploy, and test native PL/SQL web applications in secured and unsecured DADs. You can find complete re-runnable scripts for this article on github.com at the following URL.

4490 3 /
Follow / 8 Dec 2016 at 3:25pm

Nice article, I finally got rid of the login screen. One remark though: after configuring all this, the database must be restarted, if the login screen persists.

Follow / 21 Dec 2016 at 10:43pm

Robert, Actually, the login is part of the browser cache. You just need to shutdown and restart the browser.

Follow / 31 Mar 2017 at 10:43pm

This is a great article its neat to see that you can implement this with Oracle. However I did run into some trouble when trying to enter the URL for the anonymous user. After some trial and error I have discovered that it works when you used the URL oracle12c/.../helloworld2 instead of the posted http://oracle12c/db/helloworld .