3.9. How-to for OX App Suite#

This section provides a how-to for building a packaged integration for OX App Suite as an example. After reading this section, you will know how to use the different plugins described in Packaged integrations to create a packaged integration to connect OX App Suite to Nubus for Kubernetes. The packaged integration for OX App Suite is an example for a rather complex one, because it uses all available plugin types. For a less complex packaged integration that covers only a few plugin types, see How-to for Nextcloud.

This section focuses on the following objectives:

  1. The Portal Service provides a tile that links to the OX App Suite instance.

  2. OX App Suite uses Nubus for Kubernetes as its identity management source. Identity administrators can use Nubus to decide which user accounts or user groups may use OX App Suite.

  3. Provide management capability in the Management UI for the following OX App Suite capabilities:

    Access Profile

    OX App Suite provides access profiles to limit access to available modules in OX on a per context or per-user basis. For more information, see the links to the OX documentation later.

    Functional Account

    Functional accounts in OX App Suite are secondary mailboxes for roles or teams, such as info@example.com or support@example.com. A functional account has user accounts assigned that have access to it. For more information, see the links to the OX documentation later.

    OX Context

    OX App Suite uses contexts to collect users, groups, and resources for collaboration in a virtual space. Data from one context isn’t visible to other contexts. For more information, see the links to the OX documentation later.

    OX Resources

    They’re for management of resources such as rooms or equipment that users can book for appointments. For more information, see the links to the OX documentation later.

  4. The Management UI has additional modules to administer contexts, functional mailboxes, and resources in OX App Suite.

This how-to addresses software developers and describes the steps to create the packaged integration:

  1. Validate that you meet the Prerequisites.

  2. Create the Packaged integration directory structure.

  3. Prepare the plugins.

  4. Bundle the plugins in a container image as packaged integration.

  5. Publish packaged integration.

  6. Announce packaged integration.

Hint

This how-to refers to numerous files that you need to download for the packaged integration. To keep the content of this how-to and files consistent, the links point to a Git repository and the files’ distinct commits.

The last review of this content and the files was on 6. March 2025.

Hint

This how-to shows content of files that you add to the packaged integration, where suitable and where the file content length is suitable for presentation. However, to not exceed the space for presentation, in most cases the listing provide excerpts or sections don’t show the file content at all, when it’s too long.

See also

Here you find links to resource in the documentation of Open-Xchange about OX App Suite that the text mentioned before:

Open-Xchange module access

for information about available values and their meaning.

Secondary Mail Accounts

for information about secondary mail accounts, also known as functional accounts in the Nubus context.

Context management - Open-Xchange

for information about contexts in OX App Suite.

Resource management - Open-Xchange

for information about resource management in OX App Suite.

3.9.1. Prerequisites#

To go through this how-to a computer is necessary where you can create a directory structure and files. You need the knowledge listed in Audience and required knowledge.

3.9.2. Packaged integration directory structure#

Before you begin, make sure that you meet the prerequisites listed in Prerequisites.

To begin with this how-to, you need to create the directory structure shown in Listing 3.25 on your local computer. During this how-to, you add files to subdirectories in each step. At the end, the structure contains all the files required for the packaged integration.

You can use a different top-level directory name. However, keep the names of the docker and plugins directories and their subdirectories for consistency reasons and to keep the bundle step pragmatic.

You can place the directory structure under a version control system to track all the changes over time.

Listing 3.25 Project directory structure for OX App Suite packaged integration#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    ├── syntax.d
    ├── udm-data-loader
    ├── umc-icons
    └── umc-modules

Tip

To better get along, you find a description of the expected directory structure after each step in the boxes marked with . Open it to see the updated directory structure.

3.9.3. Prepare the plugins#

Before you continue, make sure that you have completed the steps in Packaged integration directory structure.

The packaged integration for OX App Suite comprises various plugins for Nubus for Kubernetes. This section describes how you create and add these plugins to the directory structure.

  1. Add LDAP schemas for additional data structures in the Directory Service.

  2. Add extended attributes for directory objects related to OX App Suite.

  3. Add LDAP search user so that OX App Suite can access the Directory Service.

  4. Add default OX context and containers for the OX context and containers containing the directory objects.

  5. Add UMC policies for OX App Suite UMC module.

  6. Add tile for Portal Service that points users to OX App Suite.

  7. Add UDM syntax to add syntax definitions for validating user input.

  8. Add UDM hooks to add business logic for user input validation.

  9. Add UDM handlers to define UDM modules with business logic and presentation layout.

  10. Add UMC module to present the UDM modules for OX App Suite in the Management UI.

3.9.3.1. Add LDAP schemas#

An LDAP schema defines the data model in the Directory Service. This plugin type allows extending the data model to store additional information with an object, and even add object classes. For more information, see LDAP schema.

Identity administrators can control which user or user group may access OX App Suite. Operators can then configure OX App Suite to evaluate these attributes. Therefore, the OX App Suite packaged integration provides an LDAP schema to add application specific attributes and object classes to achieve these use cases, and to support the management of the OX App Suite capabilities access profiles, functional accounts, OX context, and OX resources.

Important

The packaged integration for OX App Suite with Nubus relies on this exact LDAP schema to work properly. Don’t modify it.

To add the LDAP schema, download, and add the following files to the plugins/ldap-schema/ directory in your packaged integration:

The ox.schema LDAP schema is almost 1000 lines long, making it unsuitable for presentation in this section. For details, take a look at the previously linked file.

Directory structure with added LDAP schema files

After adding the LDAP schema files, your packaged integration directory structure looks like Listing 3.26.

Listing 3.26 Directory structure with LDAP schema files#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    ├── udm-data-loader
    ├── umc-icons
    └── umc-modules

3.9.3.2. Add extended attributes#

Extended attributes are a feature of UDM that provides a mapping between an input widget and a UDM attribute. You can use the UDM HTTP REST API to configure extended attributes. The UDM data loader plugin automates the process of configuring extended attributes for the OX App Suite packaged integration. For more information about the UDM data loader, see UDM data loader.

The packaged integration for OX App Suite uses extended attributes to store per-user configuration attributes. OX App Suite evaluates and uses these attributes in LDAP search filters, or for mapping them to its properties. When an operator configures OX App Suite to use the directory service in Nubus, they have to provide the search filter strings, as well as names of the attributes that store certain properties. This section mentions attribute names for illustration and to match the default configuration of OX App Suite.

To add the extended attributes, download, and add the 30-ox-connector.yaml file to the plugins/udm-data-loader/ directory in your packaged integration. The YAML file contains the definition for 78 extended attributes. Each extended attribute defines a short and a long description that give you an impression of their purpose.

For all extended attributes, notice the template variable {{ ldapBaseDn }} in the position field of each YAML directive. Nubus for Kubernetes automatically replaces the variable with its respective value during the installation of the packaged integration.

Tip

The UDM data loader provides a template mechanism and uses Jinja2. You can use the template mechanism to make values for the data loader configurable, for example passwords and other environment specific data. Template variables allow the operator to choose their own values. For more information, see Template variables in the data loader.

Listing all extended attributes here would exceed the scope of this how-to. However, it’s worth to describe the following attributes in detail:

isOxUser

The attribute stores whether a user has access to OX App Suite. Its default property has the value OK. See Listing 3.27. It means that UDM automatically allows newly created user accounts to access OX App Suite, if isOxUser wasn’t set explicitly during user account creation.

Note

User accounts that existed before the operator installs the packaged integration, have an undefined value for isOxUser. Users with these user accounts don’t have access to OX App Suite until the identity administrator changes the property value explicitly.

Listing 3.27 Definition for the isOxUser extended attribute#
---
action: create
module: settings/extended_attribute
position: cn=open-xchange,cn=custom attributes,cn=univention,{{ ldapBaseDn }}
properties:
  name: "isOxUser"
  default: OK
  module: [users/user]
  ldapMapping: isOxUser
  objectClass: oxUserObject
  shortDescription: Activate User in OX (unchecking will delete!)
  longDescription: Activate User in OX (unchecking will delete!)
  translationShortDescription:
    de_DE: In Open-Xchange aktivieren (Deaktivieren löscht!)
  translationLongDescription:
    de_DE: In Open-Xchange aktivieren (Deaktivieren löscht!)
  tabName: OX App Suite
  overwriteTab:
  valueRequired: false
  CLIName: isOxUser
  syntax: OkOrNot
  tabAdvanced:
  mayChange: true
  multivalue: false
  deleteObjectClass: true
  tabPosition: 1
  overwritePosition:
  doNotSearch: false
  hook: oxUserDefaults
  groupName: Open-Xchange
  groupPosition: 1
oxContextUser

The attribute stores the OX context where the user account is part of. By default, Nubus places all users inside the same OX context. The default OX context comes from the {{ oxDefaultContext }} template variable. It also defines the custom syntax oxContextSelect. See Listing 3.28.

Listing 3.28 Definition for the isOxUser extended attribute#
---
action: create
module: settings/extended_attribute
position: cn=open-xchange,cn=custom attributes,cn=univention,{{ ldapBaseDn }}
properties:
  name: oxContextUser
  default: "{{ oxDefaultContext }}"
  module: [users/user]
  ldapMapping: oxContextIDNum
  objectClass: oxUserObject
  shortDescription: OX context
  longDescription: OX context, the user will be created in
  translationShortDescription:
    de_DE: OX-Kontext
  translationLongDescription:
    de_DE: OX-Kontext, in dem der Benutzer angelegt wird
  tabName: OX App Suite
  translationTabName:
    de_DE: OX App Suite
  overwriteTab:
  valueRequired: false
  CLIName: oxContext
  syntax: oxContextSelect
  tabAdvanced:
  mayChange: true
  multivalue: false
  deleteObjectClass: false
  tabPosition: 2
  overwritePosition:
  doNotSearch: true
  hook: oxContextRW
  groupName: Open-Xchange
  groupPosition: 1
  disableUDMWeb: false
oxContextResource

The attribute sets the OX context for an OX resource. See Listing 3.29.

Notice the template variable {{ oxDefaultContext }}. Note that template variable for announcement to operators.

Listing 3.29 Definition for the oxContextResource extended attribute#
---
action: create
module: settings/extended_attribute
position: cn=open-xchange,cn=custom attributes,cn=univention,{{ ldapBaseDn }}
properties:
  name: oxContextResource
  default: "{{ oxDefaultContext }}"
  module: [oxresources/oxresources]
  ldapMapping: oxContextIDNum
  objectClass: oxResourceObject
  shortDescription: OX context
  longDescription: OX context, the resource will be created in
  translationShortDescription:
    de_DE: OX-Kontext
  translationLongDescription:
    de_DE: OX-Kontext, in dem die Resource angelegt wird
  tabName: OX App Suite
  translationTabName:
    de_DE: OX App Suite
  overwriteTab:
  valueRequired: false
  CLIName: oxContext
  syntax: oxContextSelect
  tabAdvanced:
  mayChange: true
  multivalue: false
  deleteObjectClass: false
  tabPosition: 1
  overwritePosition:
  doNotSearch: false
  hook: oxContextRW
  disableUDMWeb: false
  notEditable: false

The extended attributes use various syntax. Among them are default UDM syntax, such as emailAddress, OkOrNot, and string. Furthermore, some extended attributes use the following custom UDM syntax specific to OX App Suite.

  • oxaccess

  • oxContextSelect

  • oxlanguage

  • oxtimezone

For more about added custom syntax information, see Add UDM syntax.

Directory structure with added extended attributes

After adding the UDM data loader file that contains the extended attributes, your packaged integration directory structure looks like Listing 3.30.

Listing 3.30 Packaged integration directory structure after adding extended attributes#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    ├── udm-data-loader
    │   └── 30-ox-connector.yaml
    ├── umc-icons
    └── umc-modules

3.9.3.3. Add LDAP search user#

Applications like OX App Suite read the list of user accounts from the Directory Service. OpenLDAP is the Directory Service in Nubus. To access the Directory Service and read directory objects, it’s best practice to use a separate user account for each application. Therefore, the documentation usually refers to this user account with the term LDAP search user.

You need to use the UDM data loader plugin to add the LDAP search user to Nubus. The UDM data loader uses the UDM HTTP REST API to create the directory objects through UDM. For more information about the UDM data loader, see UDM data loader.

To add the LDAP search user, download, and add the 80-ox-configuration.yaml file in the plugins/udm-data-loader/ directory. The UDM data loader creates the LDAP search user in the users/ldap UDM module. Unlike the users/user UDM module which represents user accounts of people manageable by identity administrators, the users/ldap UDM module hides the LDAP search user from the user account and user group management in the Management UI. Listing 3.31 shows the relevant excerpt for the LDAP search user.

Notice the template variable oxSystemUserPassword. Remember to inform operators about the need to set a value for this variable.

Caution

Don’t hard code the user password for the LDAP search user. The UDM data loader provides a template mechanism and uses Jinja2. Using a template variable allows the operator to choose their own password when installing the packaged integration.

Tip

You can use the template mechanism to also make other values configurable. For more information, see Template variables in the data loader.

Listing 3.31 Definition for LDAP search user for OX App Suite in YAML format for the UDM data loader#
# Create system user
action: create
module: users/ldap
position: cn=users,{{ ldapBaseDn }}
properties:
  username: "oxSystemUser"
  lastname: "LDAP-system-User"
  password: {{ oxSystemUserPassword }}
  overridePWHistory: true
  overridePWLength: true
Directory structure with added LDAP search user

After you added the UDM data loader that contains the LDAP search user, your packaged integration directory structure looks like Listing 3.32.

Listing 3.32 Packaged integration directory structure after adding LDAP search user#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    └── umc-modules

See also

Identity Store and Directory Service

in Univention Nubus for Kubernetes - Architecture Manual [1] for information about the architecture of the Identity Store and Directory Service in Nubus for Kubernetes.

3.9.3.4. Add default OX context and containers#

Besides adding extended attributes, you also need to add the default OX context and various containers for directory objects that relate to OX App Suite. The packaged integration provides its own dedicated UDM modules for managing these objects, such as oxmail/oxcontext. For additional UDM modules in this packaged integration, see Add UDM handlers.

The 30-ox-connector.yaml file, which you’ve already added to your packaged integration in Add extended attributes, adds the necessary directory objects. Listing 3.33 shows the definition of the default OX context and uses the {{ oxDefaultContext }} template variable.

Listing 3.33 Definition for the default OX context#
---
# Create default context
action: create
module: oxmail/oxcontext
position: cn=open-xchange,{{ ldapBaseDn }}
properties:
  contextid: {{ oxDefaultContext }}
  name: "{{ oxDefaultContext }}"

See also

Context management - Open-Xchange

for information about contexts in OX App Suite.

3.9.3.5. Add access profiles#

OX App Suite uses access profiles to configure permissions and determine which user account has access to functionality in OX App Suite. The packaged integration also contains the oxmail/accessprofile UDM module for managing such objects. For additional UDM modules in this packaged integration, see Add UDM handlers.

The 30-ox-connector.yaml file defines various access profiles for OX App Suite which you’ve already added to your packaged integration in Add extended attributes. Listing 3.34 shows the Webmail profile as example.

Listing 3.34 Example for definition of an access profile for OX App Suite#
---
action: create
module: oxmail/accessprofile
position: cn=accessprofiles,cn=open-xchange,{{ ldapBaseDn }}
properties:
  name: "webmail"
  displayName: "Webmail"
  contacts: true
  webmail: true
  collectemailaddresses: true
  multiplemailaccounts: true
  subscription: true

See also

Open-Xchange module access

for information about available values and their meaning.

3.9.3.6. Add UMC policies#

Policies describe administrative settings in the directory service. The packaged integration for OX App Suite adds operations for the Management UI. To enable users to use these operations, the packaged integration adds the respective policies.

To properly use the UMC module in the Management UI, you need to add UMC policies. You define them as data for the UDM data loader in the YAML format. download, and add the 33-umc-policies-default-ox.yaml file to the plugins/udm-data-loader/ directory. See the content in Listing 3.35.

Listing 3.35 Definition for the UMC policies#
# SPDX-License-Identifier: AGPL-3.0-only
# SPDX-FileCopyrightText: 2023-2025 Univention GmbH

---
action: create
module: policies/umc
position: cn=UMC,cn=policies,{{ ldapBaseDn }}
properties:
  name: default-umc-all
  allow:
    - cn=ox-functional-accounts,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
    - cn=ox-resources,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
    - cn=ox-context,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
---
action: ensure_list_contains
module: policies/umc
position: cn=default-umc-all,cn=UMC,cn=policies,{{ ldapBaseDn }}
properties:
  allow:
    - cn=ox-functional-accounts,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
    - cn=ox-resources,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
    - cn=ox-context,cn=operations,cn=UMC,cn=univention,{{ ldapBaseDn }}
---
action: ensure_list_contains
module: groups/group
position: cn=Domain Admins,cn=groups,{{ ldapBaseDn }}
policies:
  policies/umc:
    - cn=default-umc-all,cn=UMC,cn=policies,{{ ldapBaseDn }}
Directory structure with added UMC policies

After adding the UDM data loader file that contains the UMC policies, your packaged integration directory structure looks like Listing 3.36.

Listing 3.36 Packaged integration directory structure after adding UMC policies#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   ├── 33-umc-policies-default-ox.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    └── umc-modules

3.9.3.7. Add tile for Portal Service#

A portal tile adds a link to OX App Suite on the Portal Service enabling end users to navigate directly to OX App Suite. Adding a portal tile comprises the following actions:

  1. Create a portal tile, define its appearance, behavior, and visibility.

  2. Add the portal tile to a portal category where the Portal Service shows it.

Important

The Portal Service only shows portal tiles that have a reference entry in the portal category.

A portal tile is also a directory object. To add the portal tile, you need to use the UDM data loader plugin. The 80-ox-configuration.yaml file in the plugins/udm-data-loader/ directory that you added in Add LDAP search user, contains the relevant data for the portal tile. Listing 3.37 shows an excerpt for such a portal tile definition.

Notice the template variables portalOxLinkBase and ldapBaseDn. Similar to the password for the LDAP Search user in Add LDAP search user, the operator must set the value for portalOxLinkBase upon the installation of the packaged integration. Remember to inform operators about the template variables.

Nubus for Kubernetes provides the value for ldapBaseDn by default so that the operator doesn’t have to set the value for it. For more information about the template mechanism, see Template variables in the data loader.

properties.icon contains the Base64-encoded data of the OX App Suite icon for the portal tile in SVG format.

Listing 3.37 Example for the definition for the portal tile for OX App Suite#
---
# Create Ox portal tile for Domain Users
action: create_or_modify
module: portals/entry
position: cn=entry,cn=portals,cn=univention,{{ ldapBaseDn }}
properties:
  name: "ox_mail"
  icon: "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzNi4xIDI4LjMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDM2LjEgMjguMzsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiMyODRENzM7fQoJLnN0MXtmaWxsOiMzQzNDM0I7fQoJLnN0MntmaWxsOiNGRkZGRkY7fQoJLnN0M3tmaWxsOiM4Nzg3ODc7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QyIiBkPSJNMzMuNSwyNS4xVjkuN2MtMC40LDAuNS0wLjksMC45LTEuNCwxLjNjLTMuNiwyLjgtNi41LDUtOC42LDYuOGMtMC43LDAuNi0xLjIsMS0xLjcsMS4zcy0xLDAuNi0xLjcsMQoJYy0wLjcsMC4zLTEuNCwwLjUtMi4xLDAuNWgwYy0wLjYsMC0xLjMtMC4yLTIuMS0wLjVzLTEuMy0wLjctMS43LTFzLTEtMC44LTEuNy0xLjNjLTIuMS0xLjgtNS00LTguNi02LjhjLTAuNS0wLjQtMS0wLjgtMS40LTEuMwoJdjE1LjVjMCwwLjIsMC4xLDAuMywwLjIsMC41YzAuMSwwLjEsMC4zLDAuMiwwLjUsMC4yaDI5LjZjMC4yLDAsMC4zLTAuMSwwLjUtMC4yQzMzLjQsMjUuNSwzMy41LDI1LjMsMzMuNSwyNS4xeiBNMzMuNSw0VjMuNWwwLTAuMwoJTDMzLjQsM2wtMC4xLTAuMmwtMC4yLTAuMmwtMC4zLTAuMUgzLjJDMywyLjYsMi45LDIuNiwyLjgsMi44UzIuNiwzLDIuNiwzLjJjMCwyLjMsMSw0LjIsMyw1LjdjMi42LDIsNS4zLDQuMiw4LjEsNi40CgljMC4xLDAuMSwwLjMsMC4zLDAuNywwLjZjMC40LDAuMywwLjcsMC42LDAuOSwwLjhjMC4yLDAuMiwwLjUsMC40LDAuOSwwLjZjMC40LDAuMiwwLjcsMC40LDEsMC42UzE3LjgsMTgsMTgsMThoMAoJYzAuMywwLDAuNi0wLjEsMC45LTAuMnMwLjYtMC4zLDEtMC42YzAuNC0wLjIsMC43LTAuNSwwLjktMC42YzAuMi0wLjIsMC41LTAuNCwwLjktMC44czAuNi0wLjUsMC43LTAuNmMyLjgtMi4yLDUuNS00LjMsOC4xLTYuNAoJYzAuNy0wLjYsMS40LTEuNCwyLTIuM0MzMy4yLDUuNiwzMy41LDQuOCwzMy41LDR6IE0zNi4xLDMuMnYyMS45YzAsMC45LTAuMywxLjYtMC45LDIuM3MtMS40LDAuOS0yLjMsMC45SDMuMgoJYy0wLjksMC0xLjYtMC4zLTIuMy0wLjlTMCwyNiwwLDI1LjFWMy4yYzAtMC45LDAuMy0xLjYsMC45LTIuM1MyLjMsMCwzLjIsMGgyOS42YzAuOSwwLDEuNiwwLjMsMi4zLDAuOVMzNi4xLDIuMywzNi4xLDMuMnoiLz4KPC9zdmc+Cg=="
  link:
    - - en_US
      - {{ portalOxLinkBase }}/appsuite/#app=io.ox/mail
  allowedGroups:
    - 'cn=Domain Users,cn=groups,{{ ldapBaseDn }}'
  linkTarget: newwindow
  description:
    de_DE: E-Mails senden und empfangen
    en_US: Send and receive emails
  displayName:
    de_DE: Open-Xchange
    en_US: Open-Xchange

3.9.3.8. Add UDM syntax#

UDM syntax defines rules to verify user input for plausibility and validity. For more information about the UDM syntax, see UDM syntax.

The UDM syntax in this packaged integration defines user input types, for example, to select OX contexts based on available OX contexts in the environment, to select supported languages, and available time zones.

To add the UDM syntax, download, and add the 50_ox.py file to the plugins/syntax.d directory in your packaged integration.

Directory structure with added UDM syntax

After adding the UDM syntax file, your packaged integration directory structure looks like Listing 3.38.

Listing 3.38 Packaged integration directory structure after adding UDM syntax#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    │   └── 50_ox.py
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   ├── 33-umc-policies-default-ox.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    └── umc-modules

3.9.3.9. Add UDM hooks#

UDM hooks extend existing UDM modules with additional attributes and logic. For more information about the UDM handlers, see UDM hooks.

The packaged integration for OX App Suite uses UDM hooks to validate user input and to make sure that directory objects related to OX App Suite are consistent and plausible. This packaged integration defines the following UDM hooks:

oxAccess

This hook validates that user accounts with permission to use OX App Suite have the needed properties in the correct format, such as email address and anniversary date. If the input values for the user object aren’t valid, it makes sure that the identity administrator receives a proper error message.

oxGroupHook

This UDM hook makes sure that a user group for OX App Suite has an email address that matches any of the configured email domains in Nubus.

oxUserDefaults

This UDM hook sets default values for user accounts that haven’t gone through the OX App Suite user template upon their creation. It uses the default values from the extended attributes for language and timezone, and only sets the default values if the user object already hasn’t the property.

To add the UDM hooks, download, and add the following files to the plugins/hooks.d directory in your packaged integration.

Note

When you look at the repository, you find the hook oxContextRW.py. You don’t need to add it, because it only works on the command-line for UDM that’s not available in Nubus for Kubernetes.

Directory structure with added UDM hooks

After adding the UDM hooks files, your packaged integration directory structure looks like Listing 3.39.

Listing 3.39 Packaged integration directory structure after adding UDM hooks#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    ├── hooks.d
    │   ├── oxAccess.py
    │   ├── oxGroupHook.py
    │   └── oxUserDefaults.py
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    │   └── 50_ox.py
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   ├── 33-umc-policies-default-ox.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    └── umc-modules

3.9.3.10. Add UDM handlers#

UDM handlers define a custom UDM object as a representation of a directory object. They define the process or business logic, create a mapping to create a UDM object from a directory object, and they control the presentation layout for the Management UI. For more information about the UDM handlers, see UDM handlers.

The packaged integration for OX App Suite adds several LDAP objects through the LDAP schema extension, see Add LDAP schemas. These LDAP objects need a representation and business logic in UDM. The UDM handlers provide the business logic, the mapping, and the presentation layout. The packaged integration includes the following UDM handlers to add management capabilities for the respective OX App Suite entities. For information about the entities, see the introduction to this how-to.

  • Access Profile

  • Functional Account

  • OX Context

  • OX Resources

To add the UDM handlers, download, and add the following files in their subdirectories to the plugins/handlers directory in your packaged integration:

Directory structure with added UDM handlers

After adding the UDM handlers files, your packaged integration directory structure looks like Listing 3.40.

Listing 3.40 Packaged integration directory structure after adding UDM handlers#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    │   ├── oxmail
    │   │   ├── __init__.py
    │   │   ├── accessprofile.py
    │   │   ├── functional_account.py
    │   │   └── oxcontext.py
    │   └── oxresources
    │       ├── __init__.py
    │       └── oxresources.py
    ├── hooks.d
    │   ├── oxAccess.py
    │   ├── oxGroupHook.py
    │   └── oxUserDefaults.py
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    │   └── 50_ox.py
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   ├── 33-umc-policies-default-ox.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    └── umc-modules

3.9.3.11. Add UMC module#

So far, the plugins in this packaged integration add a lot of additional data structures and directory objects to the Directory Service. The additional data structures extend existing UDM modules and even add UDM modules. To manage the additional data structures, Nubus for Kubernetes provides the capability to enhance the Management UI through so-called UMC modules. For more information about the UMC module plugin type, see UMC plugins.

This section shows how to add UMC modules to manage the following entities in OX App Suite. For information about the entities, see the introduction to this how-to.

  • OX Functional Accounts

  • OX Contexts

  • OX Resources

To add the UMC module, use the following steps:

  1. Download, and add the following icons to the plugins/umc-icons/scalable directory. They provide icons for the UMC modules for the overview page in the Management UI.

  2. Download, and add the ox-common.xml file to the plugins/umc-modules directory. Listing 3.41 shows the definition of the previously mentioned UMC modules.

    A <flavor> is a property of the UMC module for UDM and references the respective UDM module. For each flavor, the Management UI presents a separate module. Furthermore, it references an icon that the Management UI shows on its overview page.

    Finally, it provides a name and a description for each module. The Management UI shows the UMC modules on its overview page, grouped along with other modules, in the category domain.

    Listing 3.41 Definition for the UMC modules to manage capabilities for OX App Suite#
    <umc version="2.0">
      <module id="udm" icon="udm/module" version="1.0" translationId="ox-common">
        <name></name>
        <description></description>
        <flavor icon="udm-mail" id="oxmail/oxcontext">
          <name>OX Contexts</name>
          <description>Managing OX contexts</description>
        </flavor>
        <flavor icon="udm-oxmail-functional_account" id="oxmail/functional_account">
          <name>OX Functional Accounts</name>
          <description>Managing OX functional accounts</description>
        </flavor>
        <flavor icon="udm-oxresources-oxresources" id="oxresources/oxresources">
          <name>OX Resources</name>
          <description>Managing OX resources</description>
        </flavor>
        <categories>
          <category name="domain"/>
        </categories>
      </module>
    </umc>
    

Hint

If you don’t see the UMC module on the overview page of the Management UI, a UCR setting may be responsible for hiding it. Nubus for Kubernetes version 1.7.0 removes the variable global.configUcr.umc.module.udm.oxmail.oxcontext.disabled. To validate your deployment configuration for such UCR variables, use the command in Listing 3.42. For the environment variable values, see Install Univention Nubus on a Kubernetes cluster in Univention Nubus for Kubernetes - Operation Manual [2].

Listing 3.42 Investigate for UCR variable that deactivate UMC modules#
$ kubectl describe configmap \
   --namespace "$NAMESPACE_FOR_NUBUS" \
   "$RELEASE"-stack-data-ums-ucr \
   | grep "oxmail"
Directory structure with added UMC modules

After adding the UMC module file that contains the UMC modules definitions, your packaged integration directory structure looks like Listing 3.43.

Listing 3.43 Packaged integration directory structure after adding UMC policies#
ox-packaged-integration
├── docker
└── plugins
    ├── handlers
    │   ├── oxmail
    │   │   ├── __init__.py
    │   │   ├── accessprofile.py
    │   │   ├── functional_account.py
    │   │   └── oxcontext.py
    │   └── oxresources
    │       ├── __init__.py
    │       └── oxresources.py
    ├── hooks.d
    │   ├── oxAccess.py
    │   ├── oxGroupHook.py
    │   └── oxUserDefaults.py
    ├── ldap-schema
    │   ├── ox-extra.schema
    │   └── ox.schema
    ├── syntax.d
    │   └── 50_ox.py
    ├── udm-data-loader
    │   ├── 30-ox-connector.yaml
    │   ├── 33-umc-policies-default-ox.yaml
    │   └── 80-ox-configuration.yaml
    ├── umc-icons
    │   ├── udm-oxmail-functional-account.svg
    │   └── udm-oxresources-oxresources.svg
    └── umc-modules
        └── ox-common.xml

3.9.4. Build container image#

After you prepared the plugins for the packaged integration, it’s time to bundle them in a container image. This section follows the steps outlined in Bundle packaged integrations and applies them to the OX App Suite packaged integration.

To bundle the packaged integration, use the following steps:

  1. Create the Dockerfile in the docker/ directory with the content in Listing 3.44.

    Listing 3.44 Dockerfile for creating the container image for the packaged integration#
    # SPDX-License-Identifier: AGPL-3.0-only
    # SPDX-FileCopyrightText: 2024 - 2025 Univention GmbH
    
    ARG BASE_IMAGE_TAG=3.20
    ARG BASE_IMAGE=docker.io/alpine
    FROM ${BASE_IMAGE}:${BASE_IMAGE_TAG}
    
    WORKDIR /
    
    # Copy plugins of the packaged integration to the Docker image
    COPY plugins /plugins
    # Copy the plugin loader to the Docker image
    COPY docker/loader.sh /bin/loader
    
    # Create system group and system user
    RUN addgroup -S appgroup && adduser -S appuser -G appgroup
    USER appuser
    
    CMD ["/bin/loader"]
    
  2. Create the loader.sh file for the loader script in the docker/ directory with the content in Listing 3.45. For information about the loader, see Packaged integration loader.

    Listing 3.45 Loader script for copying the plugins to the target directory during installation#
    #!/bin/sh
    # SPDX-License-Identifier: AGPL-3.0-only
    # SPDX-FileCopyrightText: 2024 - 2025 Univention GmbH
    
    set -eu
    
    echo "Copying the Nubus plugins into the /target volume"
    for source in /plugins/*; do
      plugin_type=$(basename "${source}")
      target="/target/${plugin_type}"
      if [ -d "${target}" ]; then
        echo "COPY - Plugin type ${plugin_type} in /target, copying files."
        cp -av "${source}" /target
      else
        echo "SKIP - Plugin type ${plugin_type} not in /target, skipping."
      fi
    done
    
    Directory structure with added UMC modules

    Finally, your directory structure looks like Listing 3.46.

    Listing 3.46 Directory structure with Dockerfile, loader, and plugins#
    ox-packaged-integration
    ├── docker
    │   ├── Dockerfile
    │   └── loader.sh
    └── plugins
        ├── handlers
        │   ├── oxmail
        │   │   ├── __init__.py
        │   │   ├── accessprofile.py
        │   │   ├── functional_account.py
        │   │   └── oxcontext.py
        │   └── oxresources
        │       ├── __init__.py
        │       └── oxresources.py
        ├── hooks.d
        │   ├── oxAccess.py
        │   ├── oxGroupHook.py
        │   └── oxUserDefaults.py
        ├── ldap-schema
        │   ├── ox-extra.schema
        │   └── ox.schema
        ├── syntax.d
        │   └── 50_ox.py
        ├── udm-data-loader
        │   ├── 30-ox-connector.yaml
        │   ├── 33-umc-policies-default-ox.yaml
        │   └── 80-ox-configuration.yaml
        ├── umc-icons
        │   ├── udm-oxmail-functional-account.svg
        │   └── udm-oxresources-oxresources.svg
        └── umc-modules
            └── ox-common.xml
    
  3. To build the container image, run the commands shown in Listing 3.47.

    Listing 3.47 Example for building the container image for the packaged integration#
    $ export IMAGE_NAME="ox"
    
    $ cd ox-packaged-integration
    $ docker build -t "$IMAGE_NAME" -f docker/Dockerfile .
    

3.9.5. Publish packaged integration#

To make the packaged integration for Nubus for Kubernetes available to operators, you need to publish the container image to a container registry where your intended audience has access to.

To publish your container image, use the commands from the example in Listing 3.48.

Listing 3.48 Example for publishing container image with bundled packaged integration#
$ export REGISTRY="artificts.software-univention.de"
$ export REPOSITORY="nubus/images/ox-packaged-integration"
$ export IMAGE_NAME="ox"
$ export IMAGE_TAG="0.1.0"

$ docker image tag "$IMAGE_NAME" "$REGISTRY"/"$REPOSITORY"/"$IMAGE_NAME":"$IMAGE_TAG"
$ docker image push "$REGISTRY"/"$REPOSITORY"/"$IMAGE_NAME":"$IMAGE_TAG"

The environment variables used in Listing 3.48 need to reflect the host and folder structure of your container registry. An operator later uses them in their Helm values when referring to the container image of the packaged integration. Table 3.3 shows the mapping.

Table 3.3 Term mapping and description for used environment variables#

Environment variable

Description

Helm Chart key

REGISTRY

FQDN and optional port of your container registry

registry

REPOSITORY

Path to the image on the registry without trailing slash /

repository

IMAGE_NAME

The name of the container image

name

IMAGE_TAG

Your version tag or latest

tag

3.9.6. Announce packaged integration#

You need to tell operators that want to install your packaged integration where they can find the container image, what each template variable is for, and which values each variable accepts. Provide an example. This how-to defines the following template variables that you need to announce:

oxDefaultContext

The operator must define the name for the first and default context in OX App Suite.

oxSystemUserUserPassword

The operator must define a dedicated password for the LDAP search user. They must use the same password in the OX App Suite LDAP configuration for the search user.

portalOxLinkBase

The operator must set the base URL to their OX App Suite instance, for example https://ox.example.com.

Tip

You don’t need to announce the ldapBaseDn template variable, because Nubus for Kubernetes automatically fills in the value during installation. For more information, see Template variables in the data loader.