5

Прежде всего я хочу прокомментировать, что я уже проверил другие вопросы переполнения стека и реализовать свой собственный подход, основанный на ответах: https://stackoverflow.com/a/14425801/2487263 и https://stackoverflow.com/a/16101649/2487263Как обрабатывать различные проверки подлинности в Spring security 3.1?

Я пытаюсь обеспечить REST API с помощью Spring Security 3.1 в Spring 3.2, Spring MVC приложение, я использую базовый подход аутентификации с помощью простой конфигурации:

<http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint"> 
    <intercept-url pattern="/**" access="ROLE_USER"/> 
    <http-basic /> 
</http> 

Как вы можете видеть, я использую свою точку пользовательского ввода у меня есть свой собственный объект ErrorResponse, что я буду добавлять к HTTP ответ в формате json, см. код ниже:

@Component 
public class AuthenticationFailedEntryPoint implements AuthenticationEntryPoint { 
    static Logger log = Logger.getLogger(AuthenticationFailedEntryPoint.class); 

    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 
     log.error(ExceptionUtils.getStackTrace(authException)); 
     ErrorResponse errorResponse = new ErrorResponse(); 

      ... here I fill my errorResponse object ... 

     ObjectMapper jsonMapper = new ObjectMapper(); 

     response.setContentType("application/json;charset=UTF-8"); 
     response.setStatus(status); 

     PrintWriter out = response.getWriter(); 
     out.print(jsonMapper.writeValueAsString(errorResponse)); 
    } 
} 

Я попробовал подход с двумя случаями тестирования:

  1. Try потреблять одну услугу без предоставления основных заголовков аутентификации:

Это запрос/ответ:

GET http://localhost:8081/accounts/accounts?accountNumber=1013 


-- response -- 
401 Unauthorized 
Server: Apache-Coyote/1.1 

Content-Type: application/json;charset=UTF-8 

Content-Length: 320 

Date: Fri, 25 Oct 2013 17:11:15 GMT 

Proxy-Connection: Keep-alive 

{"status":401,"messages":[{"code":"000011","message":"You are not authorized to reach this endpoint"}]} 

2.- Попробуйте использовать тот же сервис, но теперь отправляете базовые аутентичные Ation заголовки с неправильным паролем:

Это запрос/ответ:

GET http://localhost:8081/accounts/accounts?accountNumber=1013 
Authorization: Basic bXl1c2VyOmdvb2RieWU= 


-- response -- 
401 Unauthorized 
Server: Apache-Coyote/1.1 

WWW-Authenticate: Basic realm="Spring Security Application" 

Content-Type: text/html;charset=utf-8 

Content-Length: 1053 

Date: Fri, 25 Oct 2013 17:03:09 GMT 

Proxy-Connection: Keep-alive 

<html> ... ugly html generated by tc server ... </html> 

Как вы можете видеть, что в первом случае точка входа была достигнута, и метод Commence был выполнен с надлежащим обращением с исключение и ответ json был возвращен. Но этого не случилось, когда пароль был неправильным.

В журналах я обнаружил, что в обоих случаях производят другой поток:

Для случая 1 (без аутентификации заголовков):

... 
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /accounts?accountNumber=1013; Attributes: [ROLE_USER] 
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.sprin[email protected]9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 
2013-10-25 13:11:15,830 DEBUG tomcat-http--13 org.springframework.security.access.vote.AffirmativeBased - Voter: [email protected], returned: -1 
2013-10-25 13:11:15,831 DEBUG tomcat-http--13 org.springframework.security.access.vote.AffirmativeBased - Voter: [email protected]ef7, returned: 0 
2013-10-25 13:11:15,831 DEBUG tomcat-http--13 org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point 
org.springframework.security.access.AccessDeniedException: Access is denied 
... 

для случая 2 (неправильный пароль):

... 
2013-10-25 13:03:08,941 DEBUG tomcat-http--11 org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'myuser' 
2013-10-25 13:03:08,941 DEBUG tomcat-http--11 org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider 
2013-10-25 13:03:09,544 DEBUG tomcat-http--11 org.springframework.security.authentication.dao.DaoAuthenticationProvider - Authentication failed: password does not match stored value 
2013-10-25 13:03:09,545 DEBUG tomcat-http--11 org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials 
2013-10-25 13:00:30,136 DEBUG tomcat-http--9 org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed 
... 

Первый случай вызывает исключение AccessDeniedException, которое улавливается и отправляется методу begin в моей точке входа, но второй случай, который вызывает исключение BadCredentialsException, не идет t o точка входа.

Странная вещь здесь является то, что метод Commence должен получить AuthenticationException, но AccessDeniedException не является AuthenticationException но BadCredentialsException есть, видеть дерево наследования от Spring безопасности 3.1 API документации:

java.lang.Object 
    extended by java.lang.Throwable 
     extended by java.lang.Exception 
      extended by java.lang.RuntimeException 
       extended by org.springframework.security.access.AccessDeniedException 

java.lang.Object 
    extended by java.lang.Throwable 
     extended by java.lang.Exception 
      extended by java.lang.RuntimeException 
       extended by org.springframework.security.core.AuthenticationException 
        extended by org.springframework.security.authentication.BadCredentialsException 

Почему метод begin вызывается с исключением, которое не является правильным типом и почему не вызывается при наличии исключения BadCredentialsException, соответствующего типу?

Отредактировано --- Реализован ответ на @Luke

Два описанных решения используют пользовательские AuthenticationEntryPoint показанных на вопросе, конфигурация должна быть изменена выбирая один из двух следующих вариантов:

  1. Добавление пользовательского BASIC_AUTH_FILTER:

    <http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint"> 
        <intercept-url pattern="/**" access="ROLE_USER"/> 
        <custom-filter position="BASIC_AUTH_FILTER" ref="authenticationFilter" /> 
    </http> 
    
    <beans:bean id="authenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter"> 
        <beans:constructor-arg name="authenticationManager" ref="authenticationManager" /> 
        <beans:constructor-arg name="authenticationEntryPoint" ref="authenticationFailedEntryPoint" /> 
    </beans:bean> 
    
  2. ИЛИ Добавление точки входа в HTTP-основной элемент, ИМО является чистым решением:

    <http create-session="stateless" entry-point-ref="authenticationFailedEntryPoint"> 
        <intercept-url pattern="/**" access="ROLE_USER"/> 
        <http-basic entry-point-ref="authenticationFailedEntryPoint" /> 
    </http> 
    
+0

Об исключении, прокомментированном в конце вопроса, кажется, что исключение AccesDeniedException переводится ExceptionTranlationFilter в исключение аутентификации. Вот почему метод begin в пользовательской точке ввода называется – raspacorp

+0

raspacorp - Как выполнить метод «начать», хотя у нас есть @ExceptionalHandler? – Prateek

+0

@pashtika Это проблема, которую я имел почти два года назад и был решен с помощью этой пользовательской точки входа. Я помню, что обработчики исключений не вылавливали это исключение, как это происходит на раннем этапе. Однако я не знаю, исправлено ли это в более поздних версиях фреймворка, и в этом случае просто добавление надлежащего обработчика исключений сделает трюк. – raspacorp

ответ

4

Я думаю, что проблема заключается в том, что после неудачной базовой аутентификации, вызов к точке входа производится непосредственно от BasicAuthenticationFilter, который по умолчанию будет встроенной реализацией.

Для этого исправьте элемент entry-point-ref attribute on the http-basic.

В качестве альтернативы вы можете определить базовый фильтр аутентификации в качестве компонента и полностью исключить пространство имен.

+0

Все еще не работает – Prateek

Смежные вопросы