public LdapContext getLdapContext(Object principal, Object credentials) throws NamingException,
            IllegalStateException {

        String url = getUrl();
        if (url == null) {
            throw new IllegalStateException("An LDAP URL must be specified of the form ldap://<hostname>:<port>");
        }

        //copy the environment template into the runtime instance that will be further edited based on
        //the method arguments and other class attributes.
        Hashtable<String, Object> env = new Hashtable<String, Object>(this.environment);

        Object authcMech = getAuthenticationMechanism();
        if (authcMech == null && (principal != null || credentials != null)) {
            //authenticationMechanism has not been set, but either a principal and/or credentials were
            //supplied, indicating that at least a 'simple' authentication attempt is indeed occurring - the Shiro
            //end-user just didn't configure it explicitly.  So we set it to be 'simple' here as a convenience;
            //the Sun provider implementation already does this same logic, but by repeating that logic here, we ensure
            //this convenience exists regardless of provider implementation):
            env.put(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION_MECHANISM_NAME);
        }
        if (principal != null) {
            env.put(Context.SECURITY_PRINCIPAL, principal);
        }
        if (credentials != null) {
            env.put(Context.SECURITY_CREDENTIALS, credentials);
        }

        boolean pooling = isPoolingConnections(principal);
        if (pooling) {
            env.put(SUN_CONNECTION_POOLING_PROPERTY, "true");
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Initializing LDAP context using URL [{}] and principal [{}] with pooling {}",
                    new Object[] {url, principal, (pooling ? "enabled" : "disabled")});
        }

        // validate the config before creating the context
        validateAuthenticationInfo(env);

        return createLdapContext(env);
    }
This implementation returns an LdapContext based on the configured JNDI/LDAP environment configuration.
The environment (Map) used at runtime is created by merging the default/configured
{@link #getEnvironment() environment template} with some runtime values as necessary (e.g. a principal and
credential available at runtime only).
<p/>
After the merged Map instance is created, the LdapContext connection is
{@link #createLdapContext(java.util.Hashtable) created} and returned.

@param principal   the principal to use when acquiring a connection to the LDAP directory
@param credentials the credentials (password, X.509 certificate, etc.) to use when acquiring a connection to the
                   LDAP directory
@return the acquired {@code LdapContext} connection bound using the specified principal and credentials.
@throws NamingException
@throws IllegalStateException
core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapContextFactory.java