/** {@inheritDoc} */
  @Override()
  public boolean hasValue(Entry entry, VirtualAttributeRule rule) {
    Backend backend = DirectoryServer.getBackend(entry.getDN());

    try {
      ConditionResult ret = backend.hasSubordinates(entry.getDN());
      return ret != null && ret != ConditionResult.UNDEFINED;
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }

      return false;
    }
  }
  /** {@inheritDoc} */
  @Override()
  public Set<AttributeValue> getValues(Entry entry, VirtualAttributeRule rule) {
    Backend backend = DirectoryServer.getBackend(entry.getDN());

    try {
      ConditionResult ret = backend.hasSubordinates(entry.getDN());
      if (ret != null && ret != ConditionResult.UNDEFINED) {
        AttributeValue value =
            AttributeValues.create(
                ByteString.valueOf(ret.toString()), ByteString.valueOf(ret.toString()));
        return Collections.singleton(value);
      }
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }
    }

    return Collections.emptySet();
  }
  /** {@inheritDoc} */
  @Override
  public void processSASLBind(BindOperation bindOperation) {
    ExternalSASLMechanismHandlerCfg config = currentConfig;
    AttributeType certificateAttributeType = this.certificateAttributeType;
    CertificateValidationPolicy validationPolicy = this.validationPolicy;

    // Get the client connection used for the bind request, and get the
    // security manager for that connection.  If either are null, then fail.
    ClientConnection clientConnection = bindOperation.getClientConnection();
    if (clientConnection == null) {
      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
      LocalizableMessage message = ERR_SASLEXTERNAL_NO_CLIENT_CONNECTION.get();
      bindOperation.setAuthFailureReason(message);
      return;
    }

    if (!(clientConnection instanceof LDAPClientConnection)) {
      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
      LocalizableMessage message = ERR_SASLEXTERNAL_NOT_LDAP_CLIENT_INSTANCE.get();
      bindOperation.setAuthFailureReason(message);
      return;
    }
    LDAPClientConnection lc = (LDAPClientConnection) clientConnection;
    Certificate[] clientCertChain = lc.getClientCertificateChain();
    if ((clientCertChain == null) || (clientCertChain.length == 0)) {
      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
      LocalizableMessage message = ERR_SASLEXTERNAL_NO_CLIENT_CERT.get();
      bindOperation.setAuthFailureReason(message);
      return;
    }

    // Get the certificate mapper to use to map the certificate to a user entry.
    DN certificateMapperDN = config.getCertificateMapperDN();
    CertificateMapper<?> certificateMapper =
        DirectoryServer.getCertificateMapper(certificateMapperDN);

    // Use the Directory Server certificate mapper to map the client certificate
    // chain to a single user DN.
    Entry userEntry;
    try {
      userEntry = certificateMapper.mapCertificateToUser(clientCertChain);
    } catch (DirectoryException de) {
      logger.traceException(de);

      bindOperation.setResponseData(de);
      return;
    }

    // If the user DN is null, then we couldn't establish a mapping and
    // therefore the authentication failed.
    if (userEntry == null) {
      bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

      LocalizableMessage message = ERR_SASLEXTERNAL_NO_MAPPING.get();
      bindOperation.setAuthFailureReason(message);
      return;
    } else {
      bindOperation.setSASLAuthUserEntry(userEntry);
    }

    // Get the userCertificate attribute from the user's entry for use in the
    // validation process.
    List<Attribute> certAttrList = userEntry.getAttribute(certificateAttributeType);
    switch (validationPolicy) {
      case ALWAYS:
        if (certAttrList == null) {
          if (validationPolicy == CertificateValidationPolicy.ALWAYS) {
            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

            LocalizableMessage message = ERR_SASLEXTERNAL_NO_CERT_IN_ENTRY.get(userEntry.getName());
            bindOperation.setAuthFailureReason(message);
            return;
          }
        } else {
          try {
            ByteString certBytes = ByteString.wrap(clientCertChain[0].getEncoded());
            if (!find(certAttrList, certBytes)) {
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

              LocalizableMessage message =
                  ERR_SASLEXTERNAL_PEER_CERT_NOT_FOUND.get(userEntry.getName());
              bindOperation.setAuthFailureReason(message);
              return;
            }
          } catch (Exception e) {
            logger.traceException(e);

            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

            LocalizableMessage message =
                ERR_SASLEXTERNAL_CANNOT_VALIDATE_CERT.get(
                    userEntry.getName(), getExceptionMessage(e));
            bindOperation.setAuthFailureReason(message);
            return;
          }
        }
        break;

      case IFPRESENT:
        if (certAttrList != null) {
          try {
            ByteString certBytes = ByteString.wrap(clientCertChain[0].getEncoded());
            if (!find(certAttrList, certBytes)) {
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

              LocalizableMessage message =
                  ERR_SASLEXTERNAL_PEER_CERT_NOT_FOUND.get(userEntry.getName());
              bindOperation.setAuthFailureReason(message);
              return;
            }
          } catch (Exception e) {
            logger.traceException(e);

            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);

            LocalizableMessage message =
                ERR_SASLEXTERNAL_CANNOT_VALIDATE_CERT.get(
                    userEntry.getName(), getExceptionMessage(e));
            bindOperation.setAuthFailureReason(message);
            return;
          }
        }
    }

    AuthenticationInfo authInfo =
        new AuthenticationInfo(
            userEntry, SASL_MECHANISM_EXTERNAL, DirectoryServer.isRootDN(userEntry.getName()));
    bindOperation.setAuthenticationInfo(authInfo);
    bindOperation.setResultCode(ResultCode.SUCCESS);
  }