public NamingProvider createProvider(
      final URI providerUri, final FastHashtable<String, Object> env) throws NamingException {
    // Legacy naming constants
    final Endpoint endpoint = getEndpoint(env);
    final String callbackClass = getStringProperty(CALLBACK_HANDLER_KEY, env);
    final String userName = getStringProperty(Context.SECURITY_PRINCIPAL, env);
    final String password = getStringProperty(Context.SECURITY_CREDENTIALS, env);
    final String passwordBase64 = getStringProperty(PASSWORD_BASE64_KEY, env);
    final String realm = getStringProperty(REALM_KEY, env);

    boolean useSeparateConnection =
        Boolean.parseBoolean(String.valueOf(env.get(USE_SEPARATE_CONNECTION)));

    AuthenticationContext captured = AuthenticationContext.captureCurrent();
    AuthenticationConfiguration mergedConfiguration =
        AUTH_CONFIGURATION_CLIENT.getAuthenticationConfiguration(providerUri, captured);
    if (callbackClass != null && (userName != null || password != null)) {
      throw Messages.log.callbackHandlerAndUsernameAndPasswordSpecified();
    }
    if (callbackClass != null) {
      final ClassLoader classLoader = secureGetContextClassLoader();
      try {
        final Class<?> clazz = Class.forName(callbackClass, true, classLoader);
        final CallbackHandler callbackHandler = (CallbackHandler) clazz.newInstance();
        if (callbackHandler != null) {
          mergedConfiguration = mergedConfiguration.useCallbackHandler(callbackHandler);
        }
      } catch (ClassNotFoundException e) {
        throw Messages.log.failedToLoadCallbackHandlerClass(e, callbackClass);
      } catch (Exception e) {
        throw Messages.log.failedToInstantiateCallbackHandlerInstance(e, callbackClass);
      }
    } else if (userName != null) {
      if (password != null && passwordBase64 != null) {
        throw Messages.log.plainTextAndBase64PasswordSpecified();
      }
      final String decodedPassword =
          passwordBase64 != null
              ? CodePointIterator.ofString(passwordBase64)
                  .base64Decode()
                  .asUtf8String()
                  .drainToString()
              : password;
      mergedConfiguration =
          mergedConfiguration.useName(userName).usePassword(decodedPassword).useRealm(realm);
    }
    final AuthenticationContext context =
        AuthenticationContext.empty().with(MatchRule.ALL, mergedConfiguration);

    if (useSeparateConnection) {
      // create a brand new connection - if there is authentication info in the env, use it
      final Connection connection;
      try {
        connection = endpoint.connect(providerUri, OptionMap.EMPTY, context).get();
      } catch (IOException e) {
        throw Messages.log.connectFailed(e);
      }
      final RemoteNamingProvider provider = new RemoteNamingProvider(connection, context, env);
      connection.getAttachments().attach(PROVIDER_KEY, provider);
      return provider;
    } else if (env.containsKey(CONNECTION)) {
      final Connection connection = (Connection) env.get(CONNECTION);
      final RemoteNamingProvider provider = new RemoteNamingProvider(connection, context, env);
      connection.getAttachments().attach(PROVIDER_KEY, provider);
      return provider;
    } else {
      final Attachments attachments = endpoint.getAttachments();
      ProviderMap map = attachments.getAttachment(PROVIDER_MAP_KEY);
      if (map == null) {
        ProviderMap appearing =
            attachments.attachIfAbsent(PROVIDER_MAP_KEY, map = new ProviderMap());
        if (appearing != null) {
          map = appearing;
        }
      }
      final URIKey key =
          new URIKey(
              providerUri.getScheme(),
              providerUri.getUserInfo(),
              providerUri.getHost(),
              providerUri.getPort());
      RemoteNamingProvider provider = map.get(key);
      if (provider == null) {
        RemoteNamingProvider appearing =
            map.putIfAbsent(
                key, provider = new RemoteNamingProvider(endpoint, providerUri, context, env));
        if (appearing != null) {
          provider = appearing;
        }
      }
      return provider;
    }
  }
 private Endpoint getEndpoint(final FastHashtable<String, Object> env) {
   return env.containsKey(ENDPOINT) ? (Endpoint) env.get(ENDPOINT) : Endpoint.getCurrent();
 }