Class ActiveDirectoryRealm

  • All Implemented Interfaces:
    MBeanRegistration, Contained, GSSRealm, JmxEnabled, Lifecycle, Realm

    public class ActiveDirectoryRealm
    extends ActiveDirectoryRealmBase
    A realm which retrieves already authenticated users from Active Directory.

    Configuration

    Following options can be configured:
    • dirContextSourceName: the name of the DirContextSource in JNDI with which principals will be retrieved.
    • localDirContextSource: whether this DirContextSource is locally configured in the context.xml or globally configured in the server.xml (optional). Default value is false.
    • roleFormats: comma-separated list of role formats to be applied to user security groups. The following values are possible: sid retrieves the objectSid and sIDHistory attribute values, name retrieves the msDS-PrincipalName attribute value representing the down-level logon name format: {netbiosDomain}\{samAccountName}, and nameEx retrieves the distinguishedName and sAMAccountName attribute values and converts the DC RDNs from the DN to the Kerberos realm and appends the sAMAccountName (reversed RFC 2247) with format {realm}\{samAccountName}. Default is sid.
    • prependRoleFormat: whether the role format is prepended to the role as {roleFormat}:{role}. Default is false.
    • additionalAttributes: comma-separated list of attributes to be retrieved for the principal. Binary attributes must end with ;binary and will be stored as byte[], ordinary attributes will be stored as String. If an attribute is multivalued, it will be stored as List.
    • connectionPoolSize: the maximum amount of directory server connections the pool will hold. Default is zero which means no connections will be pooled.
    • maxIdleTime: the maximum amount of time in milliseconds a directory server connection should remain idle before it is closed. Default value is 15 minutes.

    Connection Pooling

    This realm offers a poor man's directory server connection pooling which can drastically improve access performance for non-session (stateless) applications. It utilizes a LIFO structure based on SynchronizedStack. No background thread is managing the connections. They are acquired, validated, eventually closed and opened when getPrincipal(GSSName, GSSCredential) is invoked. Validation involves a minimal and limited query with at most 500 ms of wait time just to verify the connection is alive and healthy. If this query fails, the connection is closed immediately. If the amount of requested connections exceeds the ones available in the pool, new ones are opened and pushed onto the pool. If the pool does not accept any addtional connections they are closed immediately.

    Note: This connection pool feature has to be explicitly enabled by setting connectionPoolSize to greater than zero.

    On Usernames

    This realm processes supplied usernames with different types.

    Supported Types

    Only a subset of username types are accepted in contrast to other realm implementations. Namely, this realm must know what type is passed to properly map it into Active Directory search space with a UsernameSearchMapper implementation. The supported username types are:
    • GSSName by inspecting the string name type,
    • X509Certificate by extracting the SAN:otherName field and matching for MS UPN type id (1.3.6.1.4.1.311.20.2.3).

    Note: Both types represent already authenticated users by means of a GSS and/or TLScontext.

    Canonicalization

    This realm will always try to canonicalize a given username type to a real GSSName with the string name type of KRB5_NT_PRINCIPAL (1.2.840.113554.1.2.2.1) similar to the canonicalize flag in the krb5.conf file. This makes the final GSSName fully usable in subsequent GSS-API calls.

    Referral Handling

    Active Directory uses two type of responses when it cannot complete a search request: referrals and search result references. Both are different in nature, read more about them here. For this section I will use the term referral for both types synomously as does the JNDI/LDAP Provider documentation.
    When working with the default LDAP ports (not GC) or in a multi-forest environment, it is highly likely to receive referrals (either subordinate or cross) during a search or lookup. Sun's JNDI/LDAP Provider takes the following approach to handle referrals with the java.naming.referral property and its values: ignore, throw, and follow. You can ignore referrals altogether, but the provider will still signal a PartialResultException when a NamingEnumeration is iterated. The reason is because it adds a ManageReferralControl when ignore is set and assumes that the target server will ignore referrals, but this is a misconception in this provider implementation, see here and here. It is also unclear whether Microsoft Active Directory supports this control.
    This realm will catch this exception and continue to process the enumeration. If the DirContextSource is set to throw, this realm will catch the ReferralException also, but avoid following referrals manually (for several reasons) and will continue with the process. Following referrals automatically is a completely opaque operation to the application, no ReferralException is thrown, but the referrals are handled internally and referral contexts are queried and closed. If you choose to follow referrals you must use my Active Directory DNS Locator otherwise the queries will fail and you will suffer from JDK-8161361 and JDK-8160768!

    Why do you need to use my Active Directory DNS Locator? Microsoft takes a very sophisticated approach on not to rely on hostnames because servers can be provisioned and decommissioned any time. Instead, they heavily rely on DNS domain names and DNS SRV records at runtime. I.e., an initial or a referral URL does not contain a hostname, but only a domain name. While you can connect to the service with this name, you cannot easily authenticate against it with Kerberos because one cannot bind the same SPN ldap/<dnsDomainName>@<REALM>, e.g., ldap/example.com@EXAMPLE.COM to more than one account. If you try authenticate anyway, you will receive a "Server not found in Kerberos database (7)" error. Therefore, one has to perform a DNS SRV query (_ldap._tcp.<dnsDomainName>) to test whether this name is a hostname or a domain name served by one or more servers. If it turns out to be a domain name, you have to select one target host from the query response (according to RFC 2782), construct a domain-based SPN ldap/<targetHost>/<dnsDomainName>@<REALM> or a host-based one ldap/<targetHost>@<REALM>, obtain a service ticket for and connect to that target host.

    How to handle referrals? There are several ways depending on your setup: Use the Global Catalog (port 3268) with a single forest and set referrals to ignore, or with multiple forests and set referrals to either

    • follow with a DirContextSource in your home forest and use my Active Directory DNS Locator, or
    • ignore with multiple DirContextSources, and create a CombinedRealm with one ActiveDirectoryRealm per forest.

    You will then have the principal properly looked up in Active Directory.

    Further references: How DNS Support for Active Directory Works is a good read on the DNS topic as well as Global Catalog and LDAP Searches and LDAP Referrals.

    Note: Always remember, referrals incur an amplification in time and space and make the entire process slower.

    See Also:
    ActiveDirectoryPrincipal