Wednesday, 17 July 2013

Oracle APEX - URL Checksums and JQuery Modal Dialogs

The Problem

We, like many others have stumbled upon the issue of pages not loading inside a Jquery dialog when the page access protection is set to “Arguments must have checksum”. This is an essential security feature in APEX that prevents the manipulation of the URL in APEX pages. You will see the following error when the dialog is opened:

In our example, both the edit link in the report and the Create button outside the report must be able to successfully open the DML form inside the modal window. The problem being that the page fails to load due to the checksum not being correctly generated.

We used the following JavaScript to open the JQuery dialog:

With “url” being defined in the URL field of our report's link column settings.

We changed the target of the link column in the report from “A page in this application” to “URL” and then defined the URL as:

The issue here is that there is no checksum being generated for this link, so therefore the destination page (page 3) fails to load inside the modal window because the page access protection is set to require checksum.

The Solution

Our solution is to create a hidden column in the report, and use the “Apex_util.prepare_url” function to populate this column with the relevant URL and checksum for each entry in the report. We'll then use the template variable for that column to pass the URL into the JavaScript function call for the JQuery modal dialog.

To do this, navigate to the report region, Go to the "Region Definition" tab and in "Region Source" you should add the line:

This adds the column “LINK_URL” to the report and populates it with the URL for the edit form page. This time the checksum will be generated. We must now return to the page and make this column's display type “HIDDEN”. - When adding or removing a column from a report, you may have to log out and log back into your application for the changes to take effect.

The next step is to insert the template variable (#LINK_URL#) for the hidden column into the JavaScript function call. Navigate back into the report, drill down into report attributes > column link settings and change the “URL” field to be:

Now when the edit link is clicked in the report, the modal window will open and because the checksums are being correctly generated, the page will be displayed.

There is also a problem with the “Create” button used to add entries to the report. The template variable #LINK_URL# cannot be used as it exists in the report row and not in the page.

Our solution is to create a page item on the page and set its display type as “HIDDEN” (we named this P2_HIDDEN).

We then create a dynamic action which will contain two “true” actions, both of which are to be executed when the “Create” button is clicked.

The first of these actions will be to execute some PL/SQL code to populate this new hidden item “P2_HIDDEN” with the URL to open a blank DML form. We still need to generate a checksum because of the clear cache parameter. So the first “true” action should be:

PL/SQL Code: :P2_HIDDEN := Apex_util.prepare_url('f?p=&APP_ID.:3:&SESSION.::&DEBUG.:3:');
As you can see, one difference here is that we no longer need to include “empno” as this page is for creating a new entry, not editing a current one. Because of this we have also included '3' in the clear cache portion of the URL. We also set “Page items to return” as the hidden page item, in this case it would be “P2_HIDDEN”. This ensures the new value is returned into the page.

Now that the new hidden item has been populated with the URL we must create a second “true” action to execute the JavaScript code necessary to pass the value of “P3_HIDDEN” into the Javascript function and successfully open the URL in the modal dialog window. This true action should be:

JavaScript Code: mymodal($v('P2_HIDDEN'))

The edit link in the report and the create button will now function as intended. The modal dialog window will open with the correct page and the checksum will have been generated in the URL allowing you to maintain the page access protection and avoid URL manipulation.

4 comments:

Great post, thank you! I've been thinking about the same problem just a couple weeks ago as well. I came up with the same solution for the first example.

Is there a specific reason why you choose to use a dynamic action in the second example?

Wouldn't it be easier and more secure to use a before header computation to get the url and write it to the hidden item?The JavaScript to open the modal dialog could then be written in the url attribute of the button itself (or in a DA, that you can choose).

This way, you can skip the additional request when the button is clicked.The url isn't about to change anywhay so why perform another request?

Yes, that way would work just as well (both methods are as secure as each other afaict). We wanted to keep the Dynamic Actions 'together' in one button to make it clearer exactly what was happening on the click. Having a "header computation" and the Javascript in the Button would, as you say, save the DA request.

We are seeing quite a few systems which separate the Javascript out from APEX in this manner as well as prioritising code maintainablility, this post reflected that particular approach.

We did try to use a 'Set Value' DA to store the URL in the Value of the Button, but for some reason it changed the 'Text' of the button (incorrectly imho). Hence the requirement for the hidden item.

Great one! I had a simular problem in a report that opens an iFrame to show details. It worked fine... until I siwtched on the session state protection :)Adding a column with the preopared url to the report solved the trick.Thanks a lot.