class LogsearchAuthenticationProvider extends LogsearchAbstractAuthenticationProvider {

  @Override
  public Authentication authenticate(Authentication inAuthentication) throws AuthenticationException {
    logger.info("Authenticating user:" + inAuthentication.getName() + ", userDetail=" + inAuthentication.toString());
    logger.info("authentication.class=" + inAuthentication.getClass().getName());

    HashMap<String, Object> auditRecord = new HashMap<String, Object>();
    auditRecord.put("user", inAuthentication.getName());
    auditRecord.put("principal", inAuthentication.getPrincipal().toString());
    auditRecord.put("auth_class", inAuthentication.getClass().getName());
    if (inAuthentication instanceof UsernamePasswordAuthenticationToken) {
      UsernamePasswordAuthenticationToken authClass = (UsernamePasswordAuthenticationToken) inAuthentication;
      Object details = authClass.getDetails();
      if (details instanceof WebAuthenticationDetails) {
        WebAuthenticationDetails webAuthentication = (WebAuthenticationDetails) details;
        auditRecord.put("remote_ip", webAuthentication.getRemoteAddress());
        auditRecord.put("session", webAuthentication.getSessionId());
      }
    }
    
    boolean isSuccess = false;
    try {
      Authentication authentication = inAuthentication;
      AuthenticationException authException = null;
      
      for (AuthMethod authMethod : AuthMethod.values()) {
        try {
          authentication = doAuth(authentication, authMethod);
          if (authentication != null && authentication.isAuthenticated()) {
            logger.info("Authenticated using method=" + authMethod.name() + ", user=" + authentication.getName());
            auditRecord.put("result", "allowed");
            isSuccess = true;
            auditRecord.put("authType", authMethod.name());
            return authentication;
          }
        } catch (AuthenticationException ex) {
          if (authException == null) {
            authException = ex;
          }
        } catch (Exception e) {
          logger.error(e, e.getCause());
        }
      }

      auditRecord.put("result", "denied");
      logger.warn("Authentication failed for user=" + inAuthentication.getName() + ", userDetail=" + inAuthentication.toString());
      if (authException != null) {
        auditRecord.put("reason", authException.getMessage());
        throw authException;
      }
      return authentication;
    } finally {
      String jsonStr = JSONUtil.mapToJSON(auditRecord);
      auditLogger.log(isSuccess ? Level.INFO : Level.WARN, jsonStr);
    }
  }

}