class AmbariLdapBindAuthenticator extends AbstractLdapAuthenticator {

  @Override
  public DirContextOperations authenticate(Authentication authentication) {

    if (!(authentication instanceof UsernamePasswordAuthenticationToken)) {
      LOG.info("Unexpected authentication token type encountered ({}) - failing authentication.", authentication.getClass().getName());
      throw new BadCredentialsException("Unexpected authentication token type encountered.");
    }

    DirContextOperations user = authenticate((UsernamePasswordAuthenticationToken) authentication);

    LdapServerProperties ldapServerProperties = ldapConfiguration.getLdapServerProperties();
    if (StringUtils.isNotEmpty(ldapServerProperties.getAdminGroupMappingRules())) {
      setAmbariAdminAttr(user, ldapServerProperties);
    }

    // Users stored locally in ambari are matched against LDAP users by the ldap attribute configured to be used as user name.
    // (e.g. uid, sAMAccount -> ambari user name )
    String ldapUserName = user.getStringAttribute(ldapServerProperties.getUsernameAttribute());
    String loginName = authentication.getName(); // user login name the user has logged in

    if (ldapUserName == null) {
      LOG.warn("The user data does not contain a value for {}.", ldapServerProperties.getUsernameAttribute());
    } else if (ldapUserName.isEmpty()) {
      LOG.warn("The user data contains an empty value for {}.", ldapServerProperties.getUsernameAttribute());
    } else if (!ldapUserName.equals(loginName)) {
      // if authenticated user name is different from ldap user name than user has logged in
      // with a login name that is different (e.g. user principal name) from the ambari user name stored in
      // ambari db. In this case add the user login name  as login alias for ambari user name.
      LOG.info("User with {}='{}' logged in with login alias '{}'", ldapServerProperties.getUsernameAttribute(), ldapUserName, loginName);

      // If the ldap username needs to be processed (like converted to all lowercase characters),
      // process it before setting it in the session via AuthorizationHelper#addLoginNameAlias
      String processedLdapUserName;
      if (ldapServerProperties.isForceUsernameToLowercase()) {
        processedLdapUserName = ldapUserName.toLowerCase();
        LOG.info("Forcing ldap username to be lowercase characters: {} ==> {}", ldapUserName, processedLdapUserName);
      } else {
        processedLdapUserName = ldapUserName;
      }

      AuthorizationHelper.addLoginNameAlias(processedLdapUserName, loginName);
    }

    return user;
  }

  public  AmbariLdapBindAuthenticator(BaseLdapPathContextSource contextSource, AmbariLdapConfiguration ldapConfiguration);

}