Tag Archives: Velocity

Apache Velocity is an open source Java-based template language for web applications. More info at http://velocity.apache.org/

Open Data Records in new Intrexx Popups

This post is in response to a question asked on the Intrexx Live! forum.

In Intrexx you can configure links to open the target page in a new window. This is called a Popup and is opposed to Tooltips which are opened within the current window, either displayed as a contex help or as a modal overlay on top of the page.

Open as Popup

To open the target page as a popup go to the Actions tab within the button properties. Under Destination chose Open as popup.

Configure a link as popup

Individual Popups from View Tables

A common use case is to have a list of data records shown in a view table. Then, by clicking on the name or description of the entries or via a dedicated button the data records open in separate popup windows. This allows the user to move and arrange the windows next to each other so that they can compare the data records.
By default, Intrexx will create a single popup window and update it when the user clicks on another entry. To have links in a view table open as individual popups open the properties window. In the Expert tab add a new attribute called sameWindow with the value no.

Individual Popups from Shaped Tables

When you want to have an especially stylized interface you usually opt for a Free Layout Table, also called Shaped Table, instead of a standard View Table. The shaped table uses a view page to display the entries. If you want to open individual popups from the shaped table’s view page, however, the above technique will fail. You can add a button to the shaped table’s view page and configure it to open as popup. But the sameWindow expert attribute has no effect here.

If you still want to have your individual popups you can just build the link manually. Place a static text field, set to Programming, on the shaped table’s view page. Using HTML and Velocity you can write the code to create the link in here. To do this you need to know a few things:

  • The neccessary HTML markup is described in the Links in Intrexx tutorial. Basically you need an A element with the data-hijax="popup" attribute and a href attribute that targets the Application (rq_AppGuid), the page to open (rq_TargetPageGuid) and the data record’s id (rq_RecId).
  • To access the current data record’s id when inside of a view table or a shaped table use the $drRecord Velocity context object: $drRecord.getRecId().
  • The url in the A element expects hex-encoded record IDs. You can use the $Codec Velocity context object for this: $Codec.hexEncodeString("Hello", "UTF-8")

The resulting code for the programmable text field looks like this:

<a href="?rq_AppGuid=D8D...E6E&rq_TargetPageGuid=ED1...EFD&rq_RecId=$Codec.hexEncodeString($drRecord.getRecId(), "UTF-8")"
  data-hijax="popup"
  class="Button_Standard">Click me</a>

Replace the GUIDs for rq_AppGuid and rq_TargetPageGuid with yours.

Referencing data fields in the page

Chances are that you do not want to have a static text like “open” as the link. You could replace the Click me in the snippet above with a nice image. Usually you will want to display the value of a data field such as a title or name and wrap that in the link. To do so you need to reference the field’s value for the current data record.

You can make individual data fields from the data group excplicitly available in view/edit pages. First, get the GUID of the data field that you want to use on your page by going to the data group and looking up the properties of the data field.
Now open the view page that is used in the shaped table and go to the Expert tab. Switch to the Settings pane and add a new setting. Up to Intrexx 5.2 you had to enter two separate keys:
page.requiredDataField.?.guid takes the GUID of the data field you want to access.
page.requiredDataField.?.identifier defines the name by which you want to access the data field. This can be any name, such as myVar, name, title, you get the idea.
By assigning a key index you map the guid to the identifier. If you want to reference multiple data fields use different keys (1, 2, 3, …) for each pair of guid and identifier.

As of Intrexx 6 this is even better supported: Simply enter page.requiredDataField.?. The dialog now contains a table where you can fill in the GUID and name.

Once you told Intrexx to make the data field available in the page you can acces it in Velocity with $drRecord.getValueHolder('<name>').getValue(). Note that you have to use $drRecord because the page is used inside a shaped table. If you want to access a data field in a normal edit or view page, use $DC.getValueHolder('<name>').getValue() instead.

The resulting code for a link that opens individual popups and displays the name of the data records looks like this:

<a href="?rq_AppGuid=D8D...E6E&rq_TargetPageGuid=ED1...EFD&rq_RecId=$Codec.hexEncodeString($drRecord.getRecId(), "UTF-8")"
  data-hijax="popup"
  class="Button_Standard">$drRecord.getValueHolder('name').getValue()</a>

Improving Intrexx Session Security

In Intrexx a user’s session is identified by the session ID. This ID is usually hidden from the user, i.e. it is stored in a browser cookie (co_SId). When the session ID is not saved as a cookie it is passed as a request parameter: default.ixsp?rq_SId=521...F0F. This is when things get dangerous: If another user gets hold of your session ID, they can log in with your account – without needing to know your username or password. If your Intrexx portal features applications with various user rights and confidential information you should take steps to prevent this from happening.

Session Hijacking

You may be thinking: Why would a user want to steal another colleague’s session ID? We are mostly speaking of intranets here. And how would they know how to do it?
The point is, when cookies are disabled in your browser, Intrexx has no choice other than to store the session ID via the URL. A few years ago, considering cookies a security risk was all the rage. Things are different today and with Web Storage there is another option with good browser support. But the way things are, the session ID gets exposed as easily as disabling cookies in your browser. To make things worse, there are still a few situations where Intrexx will put the session ID in the URL even with cookies enabled. These situations are rare and will most likely die off over the coming updates and as new versions of the software are released. Still, as of today session IDs in URLs are a viable security risk.

Session Fixation

Once you have another user’s session ID session fixation is very easy to do. All you need to do is insert the parameter to the portal’s URL: rq_SId=521...F0F. The problem is that users will share their session ID unconsciously. They have no idea what the various parameters such as rq_AppGuid, rq_RecId or rq_MenuGuid stand for and they shouldn’t need to. Often times they will want to share a specific page of the intranet with a colleague so naturally they will copy and send their URL address, just like they are used to from most websites.

Session Security Concepts

To more reliably bind a session to a specific user you need to store additional information about the client as part of their session. Then, whenever a page is opened check if these data still match the requesting client. Two common parameters for PHP session security are the following. I will use these ideas as the basis for an Intrexx implementation. To learn more about this topic, visit the PHP Security Consortium or read a book.

Check for User Agent

The user agent describes the user’s browser type. Chances are that a different user will also have a different user agent. However, this is mostly useful for public internet websites. In a closely controlled corporate environment most colleagues will be using the same browser. Another aspect to be aware of is that the user agent can be easily modified on the client-side, decreasing its reliability. Still, it is an indicator that something might be fishy. Also you might explicitly want to allow users to browse your site with two different browsers (though typically you won’t plus the average user wouldn’t know how to “reuse” their own session anyway).

Check for IP address

Most of the time different users will have different IP addresses and it is highly unlikely that they will change during a session. Again, a corporate environment can be problematic as users surfing behind a proxy will probably expose the proxy’s IP address. The PHP Security Consortium has this to say about it:

It is unwise to rely on anything at the TCP/IP level, such as IP address, because these are lower level protocols that are not intended to accommodate activities taking place at the HTTP level. A single user can potentially have a different IP address for each request, and multiple users can potentially have the same IP address.
PHP Security Consortium

So see for yourself whether this applies to your target group and environment’s set-up. Verifying the IP address can be a viable and suitable solution in some cases.

Implementing Session Security in Intrexx

The above concepts can be easily implemented in Intrexx. The client’s user agent can be retrieved using Velocity with $Browser.getUserAgentId() (or $Request.get("HTTP_USER_AGENT")), the IP address is available via $Request.REMOTE_ADDR. The full code for a Velocity macro that sets the user’s fingerprint based on these two attributes and verifies it against the current session could look like this:

#*
        Creates a fingerprint for the client based on the IP address and the user agent
        and stores it as part of the session.
        On every page where this macro is called the session will be verified against the
        actual current client data.
*#
#macro(verifySession)

        #set($strUserAgent = $Browser.getUserAgentId())
        #set($strIPAddress = "$Request.REMOTE_ADDR")
        #set($strFingerprint = "${strUserAgent}${strIPAddress}")
        #set($strFingerprint = $TextUtil.stringToHex($strFingerprint))
       
        ## Initialize Session:
        #if(!$Session.containsKey('USER_FINGERPRINT'))
                $DEBUG.info("Init session fingerprint")
                 $Session.put('USER_FINGERPRINT',$strFingerprint);
        ## If Session has been initialized...
        #else
                 #set($strOriginalFingerprint = $Session.get('USER_FINGERPRINT'))

                 ## Session does not fit to user:
                 #if($strOriginalFingerprint != $strFingerprint)
                        $DEBUG.error("[custom_preload.vm] Possible session fixation detected! Logging out...")
                        $Session.logout()
                 #end
        #end

#end

If a mismatch between the client’s data and the session data is detected $Session.logout() will immediately log out the current user and redirect them to the start page. Note, that if you have Single-Sign-On enabled, the user may not be redirected, but instead the page may open but with no working links (since the user is logged out). In that case you might want to trigger a client-side redirect, e.g. with makeAppRequest().

Normaly you would use some cryptographic hash function to obscure the stored IP address and user agent information just like you would do with passwords. For the sake of simplicity I am using $TextUtil.stringToHex($strFingerprint) instead here, which wouldn’t be a sensible solution for production code since it is reversible via $TextUtil.hexToString(). However, creating a proper getHash() function is not all that hard and nicely described in the wiki of the Open Web Application Security Project (OWASP). All you need to do is create a Java class with the given code, export as JAR-file and include it in Intrexx as a customcallable (read here). If you are running a larger portal with lots of functionality chances are that you already have some utility class that is just waiting for another useful method.

Now where to put this code? Simply copy the code into the custom_preload.vm file at internal/system/vm/custom/custom_preload.vm. This file is automatically included into each Intrexx page. Now you can call the macro #verifySession() on those pages that you want to protect using the programmable static text field or simply call it for all pages.