@Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {

    final boolean debug = logger.isDebugEnabled();
    final HttpServletRequest request = (HttpServletRequest) req;
    final HttpServletResponse response = (HttpServletResponse) res;

    try {
      Authentication credentials = extractCredentials(request);

      if (credentials != null) {

        if (debug) {
          logger.debug("Authentication credentials found for '" + credentials.getName() + "'");
        }

        Authentication authResult = authenticationManager.authenticate(credentials);

        if (debug) {
          logger.debug("Authentication success: " + authResult.getName());
        }

        Authentication requestingPrincipal = SecurityContextHolder.getContext().getAuthentication();
        if (requestingPrincipal == null) {
          throw new BadCredentialsException(
              "No client authentication found. Remember to put a filter upstream of the LoginAuthenticationFilter.");
        }

        String clientId = request.getParameter("client_id");
        if (null == clientId) {
          logger.error("No client_id in the request");
          throw new BadCredentialsException("No client_id in the request");
        }

        // Check that the client exists
        ClientDetails authenticatingClient = clientDetailsService.loadClientByClientId(clientId);
        if (authenticatingClient == null) {
          throw new BadCredentialsException("No client " + clientId + " found");
        }

        DefaultAuthorizationRequest authorizationRequest =
            new DefaultAuthorizationRequest(
                getSingleValueMap(request),
                null,
                authenticatingClient.getClientId(),
                getScope(request));
        if (requestingPrincipal.isAuthenticated()) {
          // Ensure the OAuth2Authentication is authenticated
          authorizationRequest.setApproved(true);
        }

        SecurityContextHolder.getContext()
            .setAuthentication(new OAuth2Authentication(authorizationRequest, authResult));

        onSuccessfulAuthentication(request, response, authResult);
      }

    } catch (AuthenticationException failed) {
      SecurityContextHolder.clearContext();

      if (debug) {
        logger.debug("Authentication request for failed: " + failed);
      }

      onUnsuccessfulAuthentication(request, response, failed);

      authenticationEntryPoint.commence(request, response, failed);

      return;
    }

    chain.doFilter(request, response);
  }