Openfire: Integrating with more than one External Data Source

# Integrating with more than one External Data Source

## Introduction

Openfire can be configured to use a variety of external sources for authentication, users and groups. This is useful when your users already have accounts in an external system, and you do not wish to duplicate those accounts. More information on this subject is available in the Custom Database Integration Guide, as well as the LDAP guide. You can even develop your own, custom connectivity to external data sources, as described in the Custom User Provider Guide, Custom Authentication Provider Guide and Custom Group Provider Guide.

This document takes the concept one step further, and provides instructions on how to configure Openfire to obtain its users from multiple backend systems.

Topics that are covered in this document:

## Mapped Providers

A Mapped provider differs from a Hybrid provider in that it uses a Mapper to select exactly one provider from which data is obtained, whereas a Hybrid provider will iteratively run over all configured providers until one is found that is able to fulfill the data demand.

A Mapped Provider is a provider that based on a particular characteristic of a user, uses a different provider to perform the actual operations.

Openfire provides mapped providers for the following types of data:

Authentication
  `org.jivesoftware.openfire.auth.MappedAuthProvider`
Users
  `org.jivesoftware.openfire.user.MappedUserProvider`
Groups
  `org.jivesoftware.openfire.group.MappedGroupProvider`
User Properties
  `org.jivesoftware.openfire.user.property.MappedUserPropertyProvider`

A Mapped Provider is configured with a Mapper. The Mapper will determine which secondary provider to use for a particular user. Openfire provides the following types of Mappers:

- `Authorization Based Mapper` -- to draw administrative users from another source than the regular, non-administrative users.
- `Property Based Mapper` -- uses Openfire system properties (that hold a list of usernames) to relate specific users to specific providers.

For each type of data, these Mappers are available

| Authorization Based | Property Based
--- | --- | ---
Authentication | `org.jivesoftware.openfire.auth.AuthorizationBasedAuthProviderMapper` | `org.jivesoftware.openfire.auth.PropertyBasedAuthProviderMapper`
Users | `org.jivesoftware.openfire.user.AuthorizationBasedUserProviderMapper` | `org.jivesoftware.openfire.user.PropertyBasedUserProviderMapper`
Groups | `org.jivesoftware.openfire.group.AuthorizationBasedGroupProviderMapper` | `org.jivesoftware.openfire.group.PropertyBasedGroupProviderMapper`
User Properties | `org.jivesoftware.openfire.user.property.AuthorizationBasedUserPropertyProviderMapper` | `org.jivesoftware.openfire.user.property.PropertyBasedUserPropertyProviderMapper`

### Example Configuration

An elaborate example, including configuration examples, of how Mapped Providers can be used is provided in the Separating Administrative Users Guide. This is a guide to setting up Openfire to work with different user stores for admins and non-administrative users, by utilizing Mapped Providers.

## Hybrid Providers

A Hybrid provider differs from a Mapped provider in that it will iteratively run over all configured providers until one is found that is able to fulfill the data demand, whereas a Hybrid provider uses a Mapper to select exactly one provider from which data is obtained.

The Hybrid variant of the providers iterates over its backing providers, operating on the first applicable instance.

Openfire provides hybrid providers for the following types of data:

Authentication
  `org.jivesoftware.openfire.auth.HybridAuthProvider`
Users
  `org.jivesoftware.openfire.user.HybridUserProvider`
Groups
  `org.jivesoftware.openfire.group.HybridGroupProvider`
User Properties
  `org.jivesoftware.openfire.user.property.HybridUserPropertyProvider`

Each Hybrid provider is configured to use up to three backing providers. These are configured through properties like these for the `HybridAuthProvider`:

- `hybridAuthProvider.primaryProvider.className`
- `hybridAuthProvider.secondaryProvider.className`
- `hybridAuthProvider.tertiaryProvider.className`

The property value for each of these will be the canoncial class name of the desired backing provider. Please refer to the documentation of each Hybrid provider for the names of the properties used by that provider.

### Example Configuration

Below is a sample config file section that illustrates the usage of Hybrid providers. For brevity, this example is limited to User and Auth providers (note: the "..." sections in the examples indicate areas where the rest of the config file would exist).

First, Openfire is configured to use the Hybrid providers:

openfire.xml configuration: enable 'Hybrid Providers'

    <jive>
        ...
        <provider>
            <auth>
                <className>org.jivesoftware.openfire.auth.HybridAuthProvider</className>
            </auth>
            <user>
                <className>org.jivesoftware.openfire.user.HybridUserProvider</className>
            </user>
        </provider>
        ...
    </jive>

Next, each Hybrid provider is configured with a set of providers to use to interact with data stores. In the example below, both an LDAP store and the default Openfire data stores are used.

openfire.xml configuration: Adding specific providers

    <jive>
        ...
        <hybridAuthProvider>
            <primaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapAuthProvider</className>
            </primaryProvider>
            <secondaryProvider>
                <className>org.jivesoftware.openfire.auth.DefaultAuthProvider</className>
            </secondaryProvider>
        </hybridAuthProvider>

        <hybridUserProvider>
            <primaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapUserProvider</className>
            </primaryProvider>
            <secondaryProvider>
                <className>org.jivesoftware.openfire.user.DefaultUserProvider</className>
            </secondaryProvider>
        </hybridUserProvider>
        ...
    </jive>

The above completes the configuration of the Hybrid providers. When backing providers require additional configuration, that should be added too. Shown below is the LDAP connection configuration which will be used by the LDAP user and auth Provider. For good measure, a commonly-used property is used that defines what usernames are considered to be administrators.

openfire.xml configuration: Wrapping up configuration

    <jive>
        ...
        <ldap>
            <host>localhost</host>
            <port>389</port>
            <baseDN>ou=people,dc=springfield,dc=com</baseDN>
            <adminDN>cn=admin,dc=springfield,dc=com</adminDN>
            <adminPassword>Anytown</adminPassword>
            <startTlsEnabled>false</startTlsEnabled>
            <sslEnabled>false</sslEnabled>
        </ldap>

        <admin>
            <authorizedUsernames>bart</authorizedUsernames>
        </admin>
        ...
    </jive>

### Using more than one provider of the same type

The example above shows how a Hybrid provider is used to delegate access to two data stores of different types: an LDAP store, and Openfire's own store. What if you'd like to use two LDAP services, each on a separate host?

In the configuration example above, both the `LdapAuthProvider` and `LdapUserProvider` use the same LDAP connectivity configuration. All LDAP providers by default will use LDAP connectivity configuration as defined in the `ldap` properties. How can you configure multiple LDAP providers that each connect to a different LDAP host?

The configuration of each backing provider configured in a Hybrid provider can include an optional `config` element. This element is used to point at the property that holds the connection configuration for the provider.

In the example below, Hybrid providers are configured for both Auth and Users. Each Hybrid provider is configured to use two backing providers, that are both LDAP-based. Note how for each provider, a `config` value is provided that refers to another property, in which the LDAP connection information that's applicable to that provider is defined.

openfire.xml configuration: Using two different LDAP servers

    <jive>
        ...
        <provider>
            <auth>
                <className>org.jivesoftware.openfire.auth.HybridAuthProvider</className>
            </auth>
            <user>
                <className>org.jivesoftware.openfire.user.HybridUserProvider</className>
            </user>
        </provider>

        <hybridAuthProvider>
            <primaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapAuthProvider</className>
                <config>ldapPrimary</config>
            </primaryProvider>
            <secondaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapAuthProvider</className>
                <config>ldapSecondary</config>
            </secondaryProvider>
        </hybridAuthProvider>

        <hybridUserProvider>
            <primaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapUserProvider</className>
                <config>ldapPrimary</config>
            </primaryProvider>
            <secondaryProvider>
                <className>org.jivesoftware.openfire.ldap.LdapUserProvider</className>
                <config>ldapSecondary</config>
            </secondaryProvider>
        </hybridUserProvider>

        <ldapPrimary>
            <host>dc.springfield.com</host>
            <port>10389</port>
            <baseDN>dc=springfield,dc=com</baseDN>
            <adminDN>cn=admin,dc=springfield,dc=com</adminDN>
            <adminPassword>Anytown</adminPassword>
            <startTlsEnabled>false</startTlsEnabled>
            <sslEnabled>false</sslEnabled>
        </ldapPrimary>

        <ldapSecondary>
            <host>ldap.planetexpress.com</host>
            <port>389</port>
            <baseDN>ou=people,dc=planetexpress,dc=com</baseDN>
            <adminDN>cn=admin,dc=planetexpress,dc=com</adminDN>
            <adminPassword>GoodNewsEveryone</adminPassword>
            <startTlsEnabled>false</startTlsEnabled>
            <sslEnabled>false</sslEnabled>
            <groupSearchFilter>(objectClass=Group)</groupSearchFilter>
        </ldapSecondary>
        ...
    </jive>

## Frequently Asked Questions

#### Can I add my own Mapper?

Absolutely. You can implement your custom implementation and place the new custom library in the Openfire lib directory. This will ensure it is automatically available at startup. You can then reference it in Openfire's configuration by its canonical class name.

#### Can I use my custom auth/user/group provider in a Mapped or Hybrid provider?

Yes! If you've implemented custom code (as described in the Custom User Provider Guide, Custom Authentication Provider Guide and Custom Group Provider Guide) then you can use reference these implementations by their canonical class name in Openfire's configuration.