Configuring QDL.

Server tags

There is the server tag qdlConfigName that is used to designate the active QDL configuration. This does mean you may have several in the configuration as needed.

The QDL configuration itself

A great place to start is in the base system's configuration documentation. All of that is supported as well as extensions specific to OA4MP, which are documented here.

Additional attributes.

These are in the <qdl> tag in additional to the standard attributes:

Name Default Description
strict_acls false Enabled/disable enforcing strict access control for scripts. If this is set true, then every script must have permission granted to execute. Corollary: You must set permissions for every script to run or you will get errors if set to true.

Server mode and restricted IO for client scripts

In the standard QDL configuration there are two parameters that bear special mention here.

  • server_mode: limits various operations to the underlying OS, such as file reads and writes. Again, this does not apply to server scripts
  • restricted_io: Allows printing (when false) and logging. If set to true then no IO of any sort is allowed in client scripts.

Naming configurations and resolution

If there is a single configuration, that may be named anything you like and it will be used. If there are multiple configurations, then you should set the attribute for qdlConfigName to be whatever the active configuration is. If it is omitted, the default name of qdl-default will be used.

Scripts

Scripts at the server level are run for every client in the specified phase -- they are just standard script elements like in the client configuration. The following contract for server scripts holds for client scripts: Server script are run first, creating/updating the workspace, then the client scripts are run in the workspace.

This allows an administrator to set up state across the entire service. For instance, OA4MP has almost no concept of a user natively, since the idea is to use whatever infrastructure you have. A server script that grabs a user record and populates some data structures would allow extending OA4MP without having to alter the base server itself. Adding, say, a User and all supporting code is possible and CILogon does that, but it is a very major piece of coding and then you have to maintain it vis-a-vis OA4MP updates. QDL is much more straightforward and insulates you from server code changes.

Lifecycle of scripts

If you give a script a specific exec_phase, the server scripts are run before any other scripts. This may take a bit of planning. If you want to so something in the post_auth phase after all clients have run their handlers, then you should actually set the script for the pre_token phase to run before any other processing in the next round.

Clients may opt out

Clients may skip server scripts if their skipServerScripts flag is set.

Script syntax in the configuration file.

To add a script, put it in script tags. This uses QDL anaphors (aka scriptlets). You should read that in conjunction with the OA4MP scripting document, which is the complete documentation. server scripts

    <scripts>
       <script>
          {qdl:... 
       </script>
       <script>
          {qdl:...
       </script>
       ...
    </scripts>

You can either have one script per tag or have a single tag with an array of scripts. These are not in token handlers, but are at the top level. See the example below. There are many reasons to have scripts on the server:

  • Initializing the workspace.: This may be required if you need to extend OA4MP with a feature, such as user management or getting user metadata from some strange source.
  • Asserting claims for all clients.: Another possibility is that some projects require that grant information be supplied in the user metadata (aka the id token) for each flow so that proper billing may be done. Setting that information via a script ensures it is always done in a consistent fashion.
  • Administrative tasks: Such as regularizing all the returned claims. Some installations require certain types of information be anonymized in specific ways. A script that checks and does that is a possibility.

(Is it ugly to have JSON inside XML? Sure. But it's consistent with client configurations. shrug.)

Full example

Here is a full example taken from my testing system:

    <qdl name="qdl-test"
          enabled="true"
          debug="info"
          skipBadModulesOnLoad="true"
          restricted_io="false"
          strict_acls = "false"
          server_mode_on="true"
          script_path="vfs#/scripts/">
         <virtual_file_systems>
             <vfs type="pass_through"
                  access="rw">
                 <root_dir>/home/ncsa/dev/ncsa-git/oa4mp/server-admin/src/main/resources/qdl</root_dir>
                 <scheme><![CDATA[vfs]]></scheme>
                 <mount_point>/scripts</mount_point>
             </vfs>
         </virtual_file_systems>

         <modules>
             <module type="java"
                     import_on_start="true">
                 <class_name>edu.uiuc.ncsa.myproxy.oa4mp.qdl.OA2QDLLoader</class_name>
             </module>
         </modules>
         <modules>
             <module type="java"
                     import_on_start="true">
                 <class_name>edu.uiuc.ncsa.myproxy.oa4mp.qdl.claims.TokenHandlerLoader</class_name>
             </module>
         </modules>

         <scripts>
            <script>
            {"qdl":{"code":[
                   "x:='my_custom_claim';",
                   "say('*** IN SERVER SCRIPT');",
                   "claims.'my_claim':=x;",
                   "access_token.'my_at_claim':='my_at_claim';",
                   "refresh_token.'my_rt_claim':='my_rt_claim';"
                   ],
                   "xmd":{"exec_phase":"post_token"}
                  }
             }
           </script>

           <script>
            {"qdl":
               {
                "load":"ws_init.qdl",
                "xmd":{"exec_phase":"pre_auth","token_type":"access"},
                "args":[4,true,{"server":"localhost","port":443}]
               }
            }
           </script>

        </scripts>
    </qdl>

QDL Script Exegesis

The configuration sets the runtime environment for every QDL workspace. The script path is set, the virtual file system mounted and a couple of modules are loaded into every workspace. The two specified scripts run resp. a block of code which just sets a couple of attributes in the access and refresh token (to show it can be done), and run a script called ws_init.qdl (resolved against the script path) in the pre_auth phase, so that the workspace is set up for all clients. They are in separate script elements, though you could just run them together as elements in an array, though that gets pretty hard to parse manually. One point is that while the server has server_mode_on="true", server scripts are still allowed to run code blocks. This is because clients have no access to them. The standard caveat applies to code blocks. Keep them very simple or just run a script.

Finally, clients may be configured individually to not have these scripts run.

Modules

The module system was revised and in proved in QDL 1.5. The major innovation is that before, modules

  • Were imported into the workspace. They were not scoped consistently vis a vis other modules
  • Aliases of module were not variables, but treated differently
  • The scope policy of inheriting the current state at module creation time did allow for easy initialization, then limited their use as the current state changed.

Setting the modules in the configuration.