Requesting Permissions

1 Overview

Niagara 4 introduced the use of Java’s Security Manager. The Security Manager improves security by restricting who can run certain sections of code – if a section of code is protected, only modules granted the required Permissions will be able to run it without triggering an AccessControlException. This allows us to protect sensitive methods that could affect core functionality or reveal sensitive data from being improperly used.

Some examples of actions that are restricted by the Security Manager are:

The Policy determines what permissions each module has. In Niagara 4.0 and Niagara 4.1, the Policy is determined by policy files located in “{niagara.home}/security/policy”. This Policy is static, and third party modules have no way to modify it to request the permissions they need to get past AccessControlExceptions they might encounter. For example, a third party module has no way to write to system properties.

In Niagara 4.2, the Policy is determined by the contents of a module’s “module.xml” file, in which the module can request which permissions it needs. This allows third party modules to request and be granted permissions that they would otherwise not have.

This document describes the process of requesting additional permissions: how to request a permission, which permissions can be requested, required vs. optional permissions, and how to request permissions for program modules. In addition, we describe how an end user can view which permissions a module has been granted.

2 Requesting Permissions

This section is aimed at developers creating modules for Niagara. It describes how to request additional permissions for a module, and what permissions can be requested. In addition, it discusses how to turn off console messages during development, and how to localize the user facing content of a permission request.

2.1 How To Request Permissions

When creating a Niagara module, a developer may run into AccessControlExceptions if they are trying to access restricted functionality. In these situations, it may be possible to have their module request additional permissions. This section described the process for requesting permissions for standard Niagara modules as well as for program modules.

2.1.1 Standard Modules

When developing a standard Niagara module, the process for requesting additional permissions is simple. The first step is to create a file named ‘module-permissions.xml’ in your module’s development directory; this is the same directory the ‘module-include.xml’ file is in.

Figure 2-1 shows an example ‘module-permissions.xml’ file. Details about the various elements are given below.

<permissions>
  <niagara-permission-groups type="station"> //Type can be "station" or "workbench"
    <req-permission> // Required permission
      <name>NETWORK_COMMUNICATION</name>
      <purposeKey>This module needs to communicate with devices on port 1234.</purposeKey>
      <parameters>
        <parameter name="hosts" value="*"/>
        <parameter name="ports" value="1234"/>
      </parameters>
    </req-permission>
    <opt-permission> // Optional permission
      <name>SET_SYSTEM_TIME</name>
      <purposeKey>To do task X, this module needs to be able to set the system time.</purposeKey>
    </opt-permission>
  </niagara-permission-groups>
</permissions>

Figure 2-1: A sample module-permissions.xml

Important elements to note are:

2.1.2 Program Modules

Program modules are subject to the same restrictions as standard modules. In order to be able to perform certain tasks, they may also need to request additional permissions. The program module builder offers an interface for adding permission requests to a program module before building it. This section describes the steps to follow to add a permission request to a program module.

  1. In the ProgramModuleBuilder view, go to the “Permissions” tab (see Figure 2-2).

    The Permissions Request Tab

    Figure 2-2: The ‘Permission Requests’ tab

  2. To add permission request, click on the ‘Add Permission’ button, as shown in Figure 2-3.

    Add Permission Button

    Figure 2-3: The ‘Add Permission’ button

  3. A dialog will appear (see Figure 2-4). Edit it as appropriate for the desired permission.

    Add Permission Dialog

    Figure 2-4: The permission request dialog

    1. Select the type of permission required via the ‘Type’ drop down menu.
    2. Select the application type this request applies to via the ‘Policy Type’ drop down.
    3. Enter a purpose describing why this module needs this permission.
    4. If appropriate, enter the parameters for this permission. The parameters will be pre-filled so that only the values need to be entered. A permission with no parametrization will have a read-only text field displaying “N/A”.
    5. Select whether the permission is optional or required (see section 2.1.3)
  4. If any changes are required, a permission request can be added or removed using the ‘Edit Permission’ or ‘Remove Permissions’ command (see Figure 2-5). Although multiple permissions may be removed at once, only one can be edited at a time.

    Edit/Remove Permissions

    Figure 2-5: Editing or removing permissions

2.1.3 Required vs. Optional Permissions

Permission request specify whether the permission is required or optional.

private static void initEnvironment()
{
  try
  {
    myField = System.getenv("my_env_variable");
  }
  catch(AccessControlException e)
  {
    myField = System.getProperty("my.system.property");
  }
}

private static String myField;

Figure 2-6: Properly handling an optional permission

In Niagara 4.2, all permissions requested by a module are automatically granted. As a result, the ‘optional’ vs ‘required’ settings has no real effect other than informing the end user how the permission is being used. In future iterations, however, end users may be given the option to accept or refuse to install a module when presented with its permission requests. In this situation, a user could choose to install a module, granting all required permissions but not granting certain optional permissions.

2.2 Permission Groups

This section describes the permission groups that can be requested by a module. For each permission group, we give the permission name and severity, the underlying Java permissions that the group corresponds to, a description of what this permission allows, the parameters that can be associated with the permission, and the risk of granting that permission.

AUTHENTICATION
Allows a module to modify the principals associated with a subject.

BACKUPS
Since Niagara 4.4. Allows a module to read and manage backup files as well as restore a system from a backup.

DIAGNOSTICS
This allows a module to control runtime characteristics and monitor runtime information about the Java Virtual Machine. This could allow a module to enable various ‘verbose’ modes to access information about the class loading or memory systems, or view a list of all loaded class names, etc…

GET_ENVIRONMENT_VARIABLES
Allows a module to read the value of an environment variable.

LOAD_LIBRARIES
Allows a module to dynamically load a native code library. This allows the module to make use of pre-existing, well-tested libraries, or other external libraries.

LOGGING
Allows a module to change the logging/debug settings, either by changing what severity of message is displayed or formatting the output.

MANAGE_EXECUTION
Allows a module to modify the behaviour of any thread in the system, including system threads. This could including stopping, starting, renaming, setting the priority, etc…

MODIFY_IO_STREAMS
Allows a module to modify the standard input, output and error streams used by the system, redirecting the input/output to another location.

NETWORK_COMMUNICATION
Allows a module to open connections to and accept connections from the specified host on the specified ports.

REFLECTION Allows a module to use reflection. Adds the suppressAccessChecks named permission group, which is described in the Java API under java.lang.reflect.ReflectPermission. * Java Permissions: * permission java.lang.reflect.ReflectPermission * Risk Level: SEVERE * Risk: Granting this permission could allow an attacker to gain access to and modify private areas of the code. This can allow the attacker to gain access to private information, or alter data, which could cause the user to see incorrect data, or could even cause the system to become unstable or shut down. * Parameters: None.

RUNTIME_EXECUTION Allows a module to execute files at runtime.

SET_SYSTEM_TIME
Allows a module to modify the system time.

SHUTDOWN_HOOKS
Allows a module to execute special code when the JVM is shutting down. This could be special cleanup operations, code to send out a warning message to an administrator, saving the state of the application, etc…

SYSTEM_PROPERTIES
Allows a module to read or write the value of system properties. This could be used to make decisions based on OS information, or other information stored in the system properties.

UI
Allows a module to perform various UI related tasks, such as creating a system tray icon, or creating a window that always displays on top.

2.3 Tips and Tricks

In this section, we discuss various things you can do to improve the development process, or improve the experience of your end users.

2.3.1 Turning Off Console Output

As described in section 3.1, if the registry has changed, the user will be notified of any additional permissions that a module has requested in the console output. During development, this can mean a lot of output every time a change is made and the application restarted.

To suppress this output, you can set the “niagara.security.logPermissionGroups” system property to “false”. This must be present on startup, so it should be included in the “system.properties” file or added to the command line when starting the application. This only works if the “developer” license feature is present.

2.3.2 Localization

Permission requests are fully localizable. As a developer of a new module, the main concern is ensuring that any permission requests created are localizable. This means that the <purposeKey> element for each permission request in the “module-permissions.xml” file should, ideally, correspond to a lexicon entry in the module’s “module.lexicon” file (see Figure 2‑7 and Figure 2‑8). If the text in the <purposeKey> element doesn’t correspond to a lexicon entry, the text will be used as-is as a non-localizable description.

...
<req-permission>
  <name>NETWORK_COMMUNICATION</name>
  <purposeKey>networkComm.purpose</purposeKey>
  <parameters>
    <parameter name="hosts" value="*.domain.net"/>
    <parameter name="ports" value="25,465"/>
  </parameters>
</req-permission>
...

Figure 2‑7: Example of a lexicon key reference in module-permissions.xml

...
networkComm.purpose=This module communicates with *.domain.net servers on ports 25 and 465.
...

Figure 2‑8: Example module.lexicon entry

The <purposeKey> is the only field whose localization is handled by the module itself. All other text associated with permission requests are localized by entries in the “baja” module’s lexicon. Some examples of user facing text that can be localized are:

All of these can be found in the baja lexicon, and start with “permissions.”.

3 Verifying Permissions

Starting in Niagara 4, the Java Security Manager was turned on in order to protect core functionality and sensitive files. Starting in Niagara 4.2, modules can request additional permissions to perform actions that the Niagara Policy does not allow by default. When installing a new Niagara system, or when installing new modules to an existing Niagara system, it is important to ensure that the permissions that modules are requesting are consistent with their functionality.

There are two ways for an end user to check what permissions are being requested by a module: console output, and the new Policy spy page.

3.1 Console Logging

When starting up an application, such as Workbench or a station, we check whether the registry has changed. This can happened when starting up a fresh installation for the first time, or when installing a new module to an existing installation. If the registry has changed, all permissions requested by all modules will be printed to the console/application director output, along with the severity of the permission, associated parameters and the reason the module needs the permission, as shown in Figure 3‑1.

Console Output

Figure 3‑1: Permission requests printed out to the console

3.2 Policy Spy

In addition to the console output, the permissions granted to a module may be viewed via the Policy spy page (see Figure 3‑2). The Policy spy can be viewed at any time, and gives more detailed information that the console output, including a description of the risks associated with each permissions. The Policy spy page can be found at Spy > securityInfo > Policy Spy.

Policy Spy

Figure 3‑2: The Policy spy page