LDAP directory setup
The Connect2id server requires a database to persist various data, such as the details of registered OAuth and OpenID Connect clients. LDAP was the only supported database backend until v6.0 which can also handle PostgreSQL, MySQL and H2.
1. Supported LDAP directory servers
The Connect2id server works with any directory that implements LDAP v3, as specified in RFC 4510. The server has been successfully tested with the following open source directory software:
- OpenLDAP 2.4+
- OpenDJ 2.6+
These two directory servers have been found to perform very well, even under extreme load and with active users in the tens of millions.
Tests with the 389 Directory Server (maintained by RedHat) revealed that it cannot handle large loads well, and we don’t recommend it.
Other LDAP directories, such as MS Active Directory and Oracle Internet Directory, will probably work, but the Connect2id server hasn’t been tested with them yet.
2. LDAP directory setup
These are the general steps for setting up an LDAP directory to store Connect2id server data. Check the bottom of this guide for directory specific instructions.
-
Add required schemas
Supply the LDAP directory with the required schemas:
- Client registration schema:
oidc-client-schema-[server].ldif
- Long-lived authorisation schema:
oidc-authz-schema-[server].ldif
- Subject (end-user) session schema:
oidc-session-schema-[server].ldif
The
[server]
denotes the particular LDAP server implementation that you have, e.g.openldap
. - Client registration schema:
-
Add required indices
The following attributes should be indexed to speed up LDAP searches:
-
authzSubject
– for retrieving long-lived authorisations by subject -
authzActor
– for retrieving long-lived authorisations by actor -
authzClientID
– for retrieving long-lived authorisations by client identifier
-
-
Create directory branches for the data
Create a directory branch for each type of persisted data:
- A branch for the client registrations, e.g.
ou=clients, o=c2id
- For the authorisations, e.g.
ou=authorizations, o=c2id
- For the identifier based access tokens, e.g.
ou=idAccessTokens, o=c2id
- For the revocation journal, e.g.
ou=revocations,o=c2id
- For the subject sessions, e.g.
ou=sessions, o=c2id
- For the subject index, e.g.
ou=subjects, o=c2id
- A branch for the client registrations, e.g.
-
Create an LDAP user
Create an LDAP user for the Connect2id server with permissions to read, search, and write entries in the above mentioned branches.
For example:
cn=c2id-server, o=c2id
Do not give the LDAP user more permissions than necessary!
3. Recommendations
-
Dedicated LDAP directory: While it’s possible to share an LDAP directory with other applications, we recommend that you provision the Connect2id server with its own LDAP directory. This is good for security and ensures performance will not suffer when another application loads the directory with its own requests.
-
Clustering: For high-availability we recommend that you set up an LDAP cluster configured for multi-master or fail-over (hot-standby) operation. Note that the Connect2id server caches extensively LDAP data, and may sustain basic service (single sign-on and token issue) with the backend LDAP directory being unavailable.
-
Backup: Make regular backups of your LDAP data. The client registrations are the most critical, as they hold the credentials of each client application that relies on the Connect2id server. If the registration data is lost each client application will have to be registered again. Loss of persisted authorisations (consent) has less of an impact – all previously issued refresh tokens will become invalid and end-users will have to re-authorise their apps.
-
Security: Provision the LDAP directory with an SSL / TLS certificate to protect the communication with the Connect2id server. CA-issued as well as self-signed certificates are accepted (the latter require an extra setting).
4. Estimating LDAP storage requirements
4.1 Client registrations storage
The size of a typical OAuth 2.0 / OpenID Connect client registration is about 2 KBytes. The storage requirements for the registrations are therefore minuscule unless you intend to provide open registration with potentially thousands or millions of client applications. In such case consider using a separate LDAP directory or cluster to store the client registrations.
4.2 Long-lived authorisations storage
The size of a typical persisted authorisation begins at 1 KByte and may be take up to several KB with multiple or longer scope and claim values.
The maximum storage requirement can be calculated with the following formula:
Total client count X total end-user count X average authorisation size
For example:
- 100 client applications
- 1 million end-users
- 1 KB average authorisation size
- Required storage: 100 GB
4.3 Session storage
If end-user sessions are going to be persisted or passivated to LDAP, you have to plan storage for that as well.
To estimate the storage requirement for sessions:
Total user count X configured session quota per user X average session size
For example:
- 1 million end-users
- 5 sessions quota per user
- 1 KB average session size
- Required storage: 5 GB
5. LDAP configuration settings
When the LDAP directory is set up put down its details in the Infinispan XML configuration:
-
ldapServer.url – The LDAP directory URL(s) (host and port)
-
ldapServer.selectionAlgorithm – Specify a round-robin or fail-over mode if you have an LDAP directory cluster (two or more LDAP URLs).
-
ldapServer.connectTimeout – Provide a sensible LDAP connect timeout, in milliseconds.
-
ldapServer.security – Specify if SSL or StartTLS LDAP connection security is required.
-
ldapServer.trustSelfSignedCerts – Set to
true
if the LDAP directory has a self-signed certificate for SSL and StartTLS. -
ldapServer.connectionPoolSize – Set an LDAP connection pool size.
-
ldapUser.dn and ldapUser.password – The credentials for the LDAP user.
-
ldapDirectory.baseDN – The directory branches for the client registrations, authorisations, etc.
6. Browsing the LDAP directory
The directory content can be easily examined with a standard LDAP browser. Apache Directory Studio is probably the best and most versatile one.
Warning: Client registrations, authorisations and other persisted entries should not be edited directly via LDAP, unless the Connect2id server is shut down. The server caches data extensively and your changes may not be seen or may be overwritten. You also run the risk of corrupting the data. Use the dedicated Connect2id server web APIs instead.
7. Directory specific setup
Here you can find detailed instructions for setting up an OpenDJ or OpenLDAP directory server.
7.1 OpenDJ
These setup instructions apply to OpenDJ 2.6 and 3.0.
7.1.1 Add required schemas
Simple offline method to add the required schemas to a freshly installed OpenDJ directory:
-
Make sure the OpenDJ server is stopped. This can be done with the
bin/status
utility. To stop it run thebin/stop-ds
script in the OpenDJ installation directory. -
Save the schema LDIF files to the
config/schema
directory. Give the schema files a numeric prefix that will have them loaded after all standard schema definitions. For example:* `90-oidc-client-schema-opendj.ldif` * `91-oidc-authz-schema-opendj.ldif` * `92-oidc-session-schema-opendj.ldif`
-
Start the OpenDJ server with
bin/start-ds
.
7.1.2 Add indices
Use the OpenDJ dsconfig
utility to create indices for the authzSubject
, authzActor
and the
authzClientID
attributes (assuming the admin connector is running on
localhost at port 4444, and has the following admin credentials):
For OpenDJ 2.6:
opendj/bin/dsconfig create-local-db-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzActor \
--set index-type:equality \
--set index-entry-limit:1000000
opendj/bin/dsconfig create-local-db-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzSubject \
--set index-type:equality \
--set index-entry-limit:1000000
opendj/bin/dsconfig create-local-db-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzClientID \
--set index-type:equality \
--set index-entry-limit:1000000
For OpenDJ 3.0:
opendj/bin/dsconfig create-backend-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzSubject \
--set index-type:equality \
--set index-entry-limit:1000000
opendj/bin/dsconfig create-backend-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzActor \
--set index-type:equality \
--set index-entry-limit:1000000
opendj/bin/dsconfig create-backend-index \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret \
--backend-name userRoot \
--index-name authzClientID \
--set index-type:equality \
--set index-entry-limit:1000000
The dsconfig utility will present you with a prompt. Press f
to confirm and
finish:
Property Value(s)
-----------------------------------------------------------------------
1) attribute authzclientid
2) index-entry-limit 1000000
3) index-extensible-matching-rule No extensible matching rules will be
indexed.
4) index-type equality
?) help
f) finish - create the new Local DB Index
q) quit
OpenDJ often requires the indices to be rebuild after a new one is added. Do
that with the following command where -b
specifies the root DN of the
directory:
opendj/bin/rebuild-index \
-b o=c2id \
--rebuildAll \
--hostname localhost \
--port 4444 \
--trustAll \
--bindDN "cn=Directory Manager" \
--bindPassword secret
7.1.3 Create directory branches
To create the necessary directory branches for the various persisted data types you can use an LDIF file like this one:
dn: ou=clients,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: clients
dn: ou=authorizations,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: authorizations
dn: ou=idAccessTokens,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: idAccessTokens
dn: ou=revocations,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: revocations
dn: ou=sessions,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: sessions
dn: ou=subjects,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: subjects
Use the ldapmodify command line LDAP client (or your favourite LDAP browser) to add the branches specified in the LDIF file:
opendj/bin/ldapmodify -p 1389 -D 'cn=Directory Manager' -a -f branches.ldif
7.1.4 Create user
LDAP connections from the Connect2id server should be made under a dedicated user account, to avoid using the privileged admin account. To do that create an LDIF file specifying the account DN and password.
Example LDIF file:
dn: uid=c2id-server,o=c2id
objectClass: account
objectClass: top
objectClass: simpleSecurityObject
uid: c2id-server
userPassword: secret
description: Connect2id server account
Add the account entry with ldapmodify:
opendj/bin/ldapmodify -p 1389 -D 'cn=Directory Manager' -a -f user.ldif
The password may be set or updated separately with the ldappasswordmodify command, or again with your favourite LDAP browser.
7.1.5 Give the user appropriate permissions
Create an access control instruction to give uid=c2id-server,o=c2id access to the directory branches where Connect2id server data is to be persisted.
LDIF file:
dn: o=c2id
changetype: modify
add: aci
aci: (target="ldap:///*=*,*,o=c2id")
(version 3.0;
acl "Connect2id server permissions";
allow (all)
(userdn = "ldap:///uid=c2id-server,o=c2id");)
Apply it with ldapmodify:
opendj/bin/ldapmodify -p 1389 -D 'cn=Directory Manager' -f aci.ldif
7.2 OpenLDAP
These setup instructions apply to OpenLDAP 2.4.0 and later. Its on-line configuration permits changes during runtime and uses standard LDAP client commands to make them.
7.2.1 Add required schemas
To add the required schema files from a command line on the OpenLDAP server host:
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f oidc-client-schema-openldap.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f oidc-authz-schema-openldap.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f oidc-session-schema-openldap.ldif
Note that the OpenLDAP server must be online (running).
The ldapadd
client utility can also access a remote OpenLDAP server. For that you need to
specify the host name / IP and a bind DN / password for the configuration super
user (e.g. cn=admin,cn=config
).
7.2.2 Add indices
OpenLDAP can serve data from multiple backends. To create an index for a
particular backend you need to know its name (DN) in the cn=config
tree.
OpenLDAP is typically created with a single
backend using an LMDB
database named {1}mdb
.
You can list the available backends with ldapsearch:
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase=*)' dn
Create an LDIF
text file add-index.ldif
containing instructions to add equality (eq) indices
for the specified attributes (assuming Connect2id data is stored in the
{1}mdb
backend):
dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: authzSubject eq
olcDbIndex: authzActor eq
olcDbIndex: authzClientID eq
Apply the config changes to the OpenLDAP directory using the standard ldapmodify command:
sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f add-index.ldif
To verify that the indices have been created:
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase={1}mdb)' olcDbIndex
The resulting listing of the indices for the backend should like this:
dn: olcDatabase={1}mdb,cn=config
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
olcDbIndex: authzSubject eq
olcDbIndex: authzActor eq
olcDbIndex: authzClientID eq
7.2.3 Create directory branches
To create the necessary directory branches for the various persisted data types you can use an LDIF file like this one:
dn: ou=clients,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: clients
dn: ou=authorizations,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: authorizations
dn: ou=idAccessTokens,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: idAccessTokens
dn: ou=revocations,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: revocations
dn: ou=sessions,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: sessions
dn: ou=subjects,o=c2id
objectClass: organizationalUnit
objectClass: top
ou: subjects
Use the ldapadd command line LDAP client (or your favourite LDAP browser) to add the branches specified in the LDIF file:
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f branches.ldif
7.2.4 Create user
LDAP connections from the Connect2id server should be made under a dedicated user account, to avoid using the privileged admin account. To do that create an LDIF file specifying the account DN and password.
Example LDIF file:
dn: uid=c2id-server,o=c2id
objectClass: account
objectClass: top
objectClass: simpleSecurityObject
uid: c2id-server
userPassword: secret
description: Connect2id server account
Add the account entry with ldapadd:
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f user.ldif
The password may be set or updated separately with the ldappasswd command, or again with your favourite LDAP browser.
7.2.5 Give the user appropriate permissions
Connect to the configuration tree (with root cn=config
) of the LDAP
directory, and add new access control list (ACL) attributes to the backend
configuration (e.g. olcDatabase={1}mdb,cn=config
, see above), in order to
give tne newly created user manage access to the directory branches where the
Connect2id server data will be persisted.
Example:
olcAccess: {0}to dn.subtree="ou=clients,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
olcAccess: {1}to dn.subtree="ou=authorizations,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
olcAccess: {2}to dn.subtree="ou=idAccessTokens,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
olcAccess: {3}to dn.subtree="ou=revocations,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
olcAccess: {4}to dn.subtree="ou=sessions,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
olcAccess: {5}to dn.subtree="ou=subjects,o=c2id" by dn.base="uid=c2id,o=c2id" manage by * none
Make sure the new ACL attributes are prefixed with a number that orders them before any more general ACL rules. To do that you may have to increment the prefixes of existing LDAP ACL rules.
8. Questions?
Get in touch with Connect2id support. We’ll be delighted to help!