class AcmAuthenticationManager implements AuthenticationManager {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException
    {
        Exception lastException = null;

        try
        {
            String principal = authentication.getName();

            Map<String, AuthenticationProvider> providerMap = getSpringContextHolder().getAllBeansOfType(AuthenticationProvider.class);
            Authentication providerAuthentication = null;
            for (Map.Entry<String, AuthenticationProvider> providerEntry : providerMap.entrySet())
            {
                try
                {
                    if (providerEntry.getValue() instanceof AcmLdapAuthenticationProvider)
                    {
                        if (principal.isEmpty())
                        {
                            throw new BadCredentialsException("Empty Username");
                        }
                        AcmLdapAuthenticationProvider provider = (AcmLdapAuthenticationProvider) providerEntry.getValue();
                        String userDomain = provider.getLdapSyncService().getLdapSyncConfig().getUserDomain();
                        if (principal.endsWith(userDomain))
                        {
                            providerAuthentication = provider.authenticate(authentication);
                        }
                    }
                    else
                    {
                        providerAuthentication = providerEntry.getValue().authenticate(authentication);
                    }

                    if (providerAuthentication != null)
                    {
                        break;
                    }
                }
                catch (Exception ae)
                {
                    lastException = ae;
                }
            }

            if (providerAuthentication != null)
            {
                // Spring Security publishes an authentication success event all by itself, so we do not have to raise
                // one here.
                return getAcmAuthentication(providerAuthentication);
            }
            if (lastException != null)
            {
                AuthenticationException ae;
                if (lastException instanceof ProviderNotFoundException)
                {
                    ae = new NoProviderFoundException("Authentication problem. Please contact your administrator.");
                }
                else if (lastException instanceof BadCredentialsException)
                {
                    if (getUserDao().isUserPasswordExpired(authentication.getName()))
                    {
                        ae = new AuthenticationServiceException(
                                "Your password has expired! An email with reset password link was sent to you.", lastException);
                    }
                    else
                    {
                        ae = new AuthenticationServiceException(ExceptionUtils.getRootCauseMessage(lastException), lastException);
                    }

                }

                else
                {
                    ae = ExceptionUtils.getRootCauseMessage(lastException).contains("UnknownHostException")
                            ? new AuthenticationServiceException(
                                    "There was an unknown error in connecting with the authentication services!", lastException)
                            : new AuthenticationServiceException(ExceptionUtils.getRootCauseMessage(lastException),
                                    lastException);
                }
                getAuthenticationEventPublisher().publishAuthenticationFailure(ae, authentication);
                log.debug("Detailed exception: ", lastException);
                lastException = ae;
                throw ae;
            }
        }
        catch (RuntimeException e)
        {
            if (e instanceof NoProviderFoundException)
                throw e;
            else if (lastException != null)
                throw new AuthenticationServiceException(ExceptionUtils.getRootCauseMessage(lastException));
            else
            {
                throw new InternalAuthenticationServiceException("Unknown server error", e);
            }
        }
        // didn't get an exception, or an authentication either, so we can throw a provider not found exception,
        // since
        // either there are no providers, or no providers can handle the incoming authentication
        throw new NoProviderFoundException("Authentication problem. Please contact your administrator.");

    }

}