11.9.7. About Authorization and Group Loading with LDAP

Within the LDAP directory it is expected that there are entries for the user accounts and that there are entries for the groups, these are then cross referenced by the use of attributes. The attributes used to cross reference between the two could be a reference from the user account over to the group entry or an attribute on the group referencing the users that are members of the group. On some servers both forms of cross reference exist.

It is also common that a user would be authenticating against the server using a simple user name, when it comes to searching for the group membership information depending on the directory server in use searches could be performed using this simple name or it could be performed using the distinguished name of the users entry in the directory.

The authentication step of a user connecting to the server would always happen first, only once it has been decided that the user is successfully authenticated does the server move onto loading a users groups. As the authentication step and the authorization step both use a connection to the LDAP server the realm contains an optimization that any connection used for authentication will be reused for the group loading step. As will be shown within the configuration steps below it is possible to define rules within the authorization section to convert a users simple user name to their distinguished name, this is potentially duplicating a search that would have occurred during the authentication step so if a user name to distinguished name search has already been performed the result of that search is cached and reused without requiring a repeat.
<authorization>
    <ldap connection="...">
       <username-to-dn> <!-- OPTIONAL -->
           <!-- Only one of the following. -->
           <username-is-dn />
           <username-filter base-dn="..." recursive="..." user-dn-attribute="..." attribute="..." />
           <advanced-filter base-dn="..." recursive="..." user-dn-attribute="..." filter="..." />
        </username-to-dn>
       <group-search group-name="..." iterative="..." group-dn-attribute="..." group-name-attribute="..." >
           <!-- One of the following -->
           <group-to-principal base-dn="..." recursive="..." search-by="...">
               <membership-filter principal-attribute="..." />
           </group-to-principal>
           <principal-to-group group-attribute="..." />
       </group-search>
    </ldap>
</authorization>

Important

Some of these examples specify attributes are using the default values. They are shown here for clarity. Attributes that contain the default values are removed from the configuration when it is persisted by the server.

username-to-dn

As mentioned above there may sometimes be a need to define within the authorization configuration how to map from the user name supplied by the user being authenticated to the distinguished name of their entry within the LDAP directory. The username-to-dn element is how this is defined, this element is only required if both of the following are true:
  • The authentication step was not against LDAP.
  • The group searching is using the distinguished name during the searching.

Do try and keep the first bullet point in mind, as you read the examples below this will feel as though the authentication configuration is being duplicated and it is true that it is - if you are only using LDAP for authentication this is not required as the distinguished name will be obtained during authentication.
1:1 username-to-dn

This is the most basic form of the configuration and is used to specify that the user name entered by the remote user is actually the users distinguished name.
<username-to-dn>
   <username-is-dn />
</username-to-dn>

As this is defining a 1:1 mapping there is no additional configuration possible.
username-filter

The next option is very similar to the simple option described above for the authentication step, quite simply an attribute is specified that is searched for a match against the supplied user name.
<username-to-dn>
    <username-filter base-dn="dc=people,dc=harold,dc=example,dc=com" recursive="false" attribute="sn" user-dn-attribute="dn" />
</username-to-dn>

The attributes that can be set here are:
  • base-dn: The distinguished name of the context to begin the search.
  • recursive: Whether the search will extend to sub contexts. Defaults to false.
  • attribute: The attribute of the users entry to try and match against the supplied user name. Defaults to uid.
  • user-dn-attribute: The attribute to read to obtain the users distinguished name. Defaults to dn.
advanced-filter

The final option is to specify an advanced filter, as in the authentication section this is an opportunity to use a custom filter to locate the users distinguished name.
<username-to-dn>
    <advanced-filter base-dn="dc=people,dc=harold,dc=example,dc=com" recursive="false" filter="sAMAccountName={0}" user-dn-attribute="dn" />
</username-to-dn>

For the attributes that match the ones in the username-filter the meaning and default values are the same so I will not list them here again, this leaves one new attribute:
  • filter: Custom filter used to search for a users entry where the user name will be substituted in the {0} place holder.

Important

The XML must remain valid after the filter is defined so if any special characters are used such as & ensure the proper form is used. For example &amp; for the & character.

The Group Search

As described above there are two different styles that can be used when searching for group membership information. The first style is where the user's entry contains an attribute that references the groups the user is a member of. The second style is where the group contains an attribute referencing the users entry.

When there is a choice of which style to use Red Hat recommends that the configuration for a user's entry referencing the group is used. This is because with this method group information can be loaded by reading attributes of known distinguished names without having to perform any searches. The other approach requires extensive searches to identify the groups that reference the user.

Before describing the configuration here are a couple of LDIF examples to illustrate this.

Example 11.1. Principal to Group - LDIF example.

This example illustrates where we have a user TestUserOne who is a member of GroupOne, GroupOne is then in-turn a member of GroupFive. The group membership is shown by the use of a memberOf attribute which is set to the distinguished name of the group the user (or group) is a member of.

It is not shown here but a user could potentially have multiple memberOf attributes set, one for each group the user is directly a member of.
dn: uid=TestUserOne,ou=users,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: inetOrgPerson
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
cn: Test User One
sn: Test User One
uid: TestUserOne
distinguishedName: uid=TestUserOne,ou=users,dc=principal-to-group,dc=example,dc=org
memberOf: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
memberOf: uid=Slashy/Group,ou=groups,dc=principal-to-group,dc=example,dc=org
userPassword:: e1NTSEF9WFpURzhLVjc4WVZBQUJNbEI3Ym96UVAva0RTNlFNWUpLOTdTMUE9PQ==

dn: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: group
objectClass: uidObject
uid: GroupOne
distinguishedName: uid=GroupOne,ou=groups,dc=principal-to-group,dc=example,dc=org
memberOf: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org

dn: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org
objectClass: extensibleObject
objectClass: top
objectClass: groupMember
objectClass: group
objectClass: uidObject
uid: GroupFive
distinguishedName: uid=GroupFive,ou=subgroups,ou=groups,dc=principal-to-group,dc=example,dc=org

Example 11.2. Group to Principal - LDIF Example

This example shows the same user TestUserOne who is a member of GroupOne which is in turn a member of GroupFive - however in this case it is an attribute uniqueMember from the group to the user being used for the cross reference.

Again the attribute used for the group membership cross reference can be repeated, if you look at GroupFive there is also a reference to another user TestUserFive which is not shown here.
dn: uid=TestUserOne,ou=users,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: inetOrgPerson
objectClass: uidObject
objectClass: person
objectClass: organizationalPerson
cn: Test User One
sn: Test User One
uid: TestUserOne
userPassword:: e1NTSEF9SjR0OTRDR1ltaHc1VVZQOEJvbXhUYjl1dkFVd1lQTmRLSEdzaWc9PQ==

dn: uid=GroupOne,ou=groups,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: Group One
uid: GroupOne
uniqueMember: uid=TestUserOne,ou=users,dc=group-to-principal,dc=example,dc=org

dn: uid=GroupFive,ou=subgroups,ou=groups,dc=group-to-principal,dc=example,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: Group Five
uid: GroupFive
uniqueMember: uid=TestUserFive,ou=users,dc=group-to-principal,dc=example,dc=org
uniqueMember: uid=GroupOne,ou=groups,dc=group-to-principal,dc=example,dc=org

General Group Searching

Before looking at the examples for the two approaches shown above we first need to define the attributes common to both of these.
<group-search group-name="..." iterative="..." group-dn-attribute="..." group-name-attribute="..." >
    ...
</group-search>
  • group-name: This attribute is used to specify the form that should be used for the group name returned as the list of groups the user is a member of, this can either be the simple form of the group name or the groups distinguished name, if the distinguished name is required this attribute can be set to DISTINGUISHED_NAME. Defaults to SIMPLE.
  • iterative: This attribute is used to indicate if after identifying the groups a user is a member of we should also iteratively search based on the groups to identify which groups the groups are a member of. If iterative searching is enabled we keep going until either we reach a group that is not a member if any other groups or a cycle is detected. Defaults to false.

Cyclic group membership is not a problem. A record of each search is kept to prevent groups that have already been searched from being searched again.

Important

For iterative searching to work the group entries need to look the same as user entries, that is the same approach used to identify the groups a user is a member of is then used to identify the groups the group is a member of. This would not be possible if say once we are talking about group to group membership the name of the attribute used for the cross reference changes or if the direction of the reference changes.
  • group-dn-attribute: On an entry for a group which attribute is it's distinguished name. Defaults to dn.
  • group-name-attribute: On an entry for a group which attribute is it's simple name. Defaults to uid.

Example 11.3. Principal to Group Example Configuration

Based on the example LDIF from above here is an example configuration iteratively loading a users groups where the attribute used to cross reference is the memberOf attribute on the user.
<authorization>
    <ldap connection="LocalLdap">
        <username-to-dn>
            <username-filter base-dn="ou=users,dc=principal-to-group,dc=example,dc=org" recursive="false" attribute="uid" user-dn-attribute="dn" />
        </username-to-dn>
        <group-search group-name="SIMPLE" iterative="true" group-dn-attribute="dn" group-name-attribute="uid">
            <principal-to-group group-attribute="memberOf" />
        </group-search>
    </ldap>
</authorization>

The most important aspect of this configuration is that the principal-to-group element has been added with a single attribute.
  • group-attribute: The name of the attribute on the user entry that matches the distinguished name of the group the user is a member of. Defaults to memberOf.

Example 11.4. Group to Principal Example Configuration

This example shows an iterative search for the group to principal LDIF example shown above.
<authorization>
      <ldap connection="LocalLdap">
          <username-to-dn>
              <username-filter base-dn="ou=users,dc=group-to-principal,dc=example,dc=org" recursive="false" attribute="uid" user-dn-attribute="dn" />
          </username-to-dn>
          <group-search group-name="SIMPLE" iterative="true" group-dn-attribute="dn" group-name-attribute="uid">
              <group-to-principal base-dn="ou=groups,dc=group-to-principal,dc=example,dc=org" recursive="true" search-by="DISTINGUISHED_NAME">
                  <membership-filter principal-attribute="uniqueMember" />
              </group-to-principal>
          </group-search>
      </ldap>
  </authorization>

Here an element group-to-principal is added, this element is used to define how searches for groups that reference the user entry will be performed, the following attributes are set:
  • base-dn: The distinguished name of the context to use to begin the search.
  • recursive: Whether sub-contexts also be searched. Defaults to false.
  • search-by: The form of the role name used in searches. Valid valids are SIMPLE and DISTINGUISHED_NAME. Defaults to DISTINGUISHED_NAME.

Within the group-to-principal element there is a membership-filter element to define the cross reference.
  • principal-attribute: The name of the attribute on the group entry that references the user entry. Defaults to member.